[version-control] Utilizzo di notebook IPython sotto controllo di versione


Answers

Abbiamo un progetto collaborativo in cui il prodotto è Jupyter Notebooks e negli ultimi sei mesi abbiamo utilizzato un approccio che funziona .ipynb : attiviamo il salvataggio automatico dei file .py e monitoriamo sia i file .ipynb file .py .

In questo modo, se qualcuno vuole visualizzare / scaricare l'ultimo blocco note, può farlo tramite github o nbviewer e, se qualcuno vuole vedere come è cambiato il codice del notebook, può semplicemente osservare le modifiche ai file .py .

Per i server notebook Jupyter , ciò può essere ottenuto aggiungendo le linee

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

al file jupyter_notebook_config.py e al riavvio del server notebook.

Se non sei sicuro in quale directory trovare il file jupyter_notebook_config.py , puoi digitare jupyter --config-dir , e se non trovi il file lì, puoi crearlo digitando jupyter notebook --generate-config .

Per i server notebook Ipython 3 , questo può essere ottenuto aggiungendo le linee

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

al file ipython_notebook_config.py e riavvio del server notebook. Queste righe provengono da problemi github, rispondono @minrk e @dror li include anche nella sua risposta SO.

Per i server notebook Ipython 2 , ciò può essere ottenuto avviando il server utilizzando:

ipython notebook --script

o aggiungendo la linea

c.FileNotebookManager.save_script = True

al file ipython_notebook_config.py e riavvio del server notebook.

Se non sei sicuro in quale directory trovare il tuo file ipython_notebook_config.py , puoi digitare ipython locate profile default , e se non trovi il file lì, puoi crearlo digitando ipython profile create .

Ecco il nostro progetto su github che sta utilizzando questo approccio : ed ecco un esempio github di esplorare recenti modifiche a un notebook .

Siamo stati molto contenti di questo.

Question

Qual è una buona strategia per mantenere i taccuini IPython sotto controllo di versione?

Il formato del notebook è abbastanza adatto per il controllo della versione: se si vuole controllare la versione del notebook e delle uscite, allora funziona abbastanza bene. Il fastidio arriva quando si vuole controllare solo la versione dell'input, escludendo le uscite della cella (chiamate anche "build products") che possono essere grandi blob binari, specialmente per film e grafici. In particolare, sto cercando di trovare un buon flusso di lavoro che:

  • mi permette di scegliere tra includere o escludere l'output,
  • mi impedisce di commettere accidentalmente l'output se non lo desidero,
  • mi permette di mantenere l'output nella mia versione locale,
  • mi permette di vedere quando ho dei cambiamenti negli input usando il mio sistema di controllo delle versioni (cioè se controllo solo le entrate ma il mio file locale ha delle uscite, allora vorrei essere in grado di vedere se gli input sono cambiati (richiede un commit ) L'uso del comando dello stato di controllo della versione registrerà sempre una differenza poiché il file locale ha delle uscite.)
  • mi consente di aggiornare il mio notebook funzionante (che contiene l'output) da un notebook pulito aggiornato. (aggiornare)

Come accennato, se ho scelto di includere gli output (che è auspicabile quando si usa nbviewer per esempio), allora tutto va bene. Il problema è quando non voglio controllare la versione dell'output. Esistono alcuni strumenti e script per rimuovere l'output del notebook, ma spesso riscontro i seguenti problemi:

  1. Per sbaglio commetto una versione con l'output, inquinando in tal modo il mio repository.
  2. Ho cancellato l'output per usare il controllo della versione, ma preferirei mantenere l'output nella mia copia locale (a volte ci vuole un po 'per riprodurlo ad esempio).
  3. Alcuni degli script che rimuovono l'output cambiano leggermente il formato rispetto all'opzione di menu Cell/All Output/Clear , creando così rumori indesiderati nelle diff. Questo è risolto da alcune delle risposte.
  4. Quando si apportano modifiche a una versione pulita del file, è necessario trovare un modo per incorporare tali modifiche nel mio blocco appunti di lavoro senza dover eseguire nuovamente tutto. (aggiornare)

Ho preso in considerazione diverse opzioni di cui discuterò in seguito, ma non ho ancora trovato una soluzione completa valida. Una soluzione completa potrebbe richiedere alcune modifiche a IPython o potrebbe basarsi su alcuni semplici script esterni. Attualmente utilizzo mercurial , ma vorrei una soluzione che funzionasse anche con git : una soluzione ideale sarebbe agnostica per il controllo della versione.

Questo problema è stato discusso molte volte, ma non esiste una soluzione definitiva o chiara dal punto di vista dell'utente. La risposta a questa domanda dovrebbe fornire la strategia definitiva. Va bene se richiede una versione recente (anche di sviluppo) di IPython o un'estensione facilmente installata.

Aggiornamento: Ho giocato con la mia versione per notebook modificata che facoltativamente salva una versione .clean con ogni salvataggio usando i suggerimenti di Gregory Crosswhite . Questo soddisfa la maggior parte dei miei vincoli ma lascia i seguenti non risolti:

  1. Questa non è ancora una soluzione standard (richiede una modifica del sorgente ipython. C'è un modo per ottenere questo comportamento con una semplice estensione? Richiede una sorta di hook di salvataggio.
  2. Un problema che ho con il flusso di lavoro corrente sta apportando modifiche. Questi entreranno nel file .clean e quindi dovranno essere integrati in qualche modo nella mia versione funzionante. (Naturalmente, riesco sempre a rieseguire il notebook, ma questo può essere un problema, specialmente se alcuni risultati dipendono da lunghi calcoli, calcoli paralleli, ecc.) Non ho una buona idea su come risolvere questo problema . Forse un flusso di lavoro che coinvolge un'estensione come ipycache potrebbe funzionare, ma sembra un po 'troppo complicato.

Gli appunti

Rimozione (rimozione) Uscita

  • Quando il notebook è in esecuzione, è possibile utilizzare l'opzione di menu Cell/All Output/Clear per rimuovere l'output.
  • Esistono alcuni script per la rimozione dell'output, come lo script nbstripout.py che rimuove l'output, ma non produce lo stesso risultato dell'utilizzo dell'interfaccia del notebook. Questo è stato infine incluso nel ipython/nbconvert , ma questo è stato chiuso affermando che le modifiche sono ora incluse in ipython/ipython , ma la funzionalità corrispondente sembra non essere stata ancora inclusa. (aggiornamento) Detto questo, la soluzione di Gregory Crosswhite mostra che questo è abbastanza facile da fare, anche senza invocare ipython/nbconvert , quindi questo approccio è probabilmente fattibile se può essere correttamente collegato. (Collegandolo ad ogni sistema di controllo di versione, comunque , non sembra una buona idea - questo dovrebbe in qualche modo collegarsi al meccanismo del notebook.)

Newsgroup

Problemi

Pull Requests




Che ne dici dell'idea discussa nel post qui sotto, dove dovrebbe essere mantenuto l'output del notebook, con l'argomento che potrebbe richiedere molto tempo per generarlo, ed è utile dal momento che GitHub può ora rendere i notebook. Sono stati aggiunti ganci di salvataggio automatico per esportare il file .py, utilizzato per diffs e .html per la condivisione con membri del team che non utilizzano notebook o git.

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




Come sottolineato, il --script è deprecato in 3.x Questo approccio può essere utilizzato applicando un post-salvataggio. In particolare, aggiungi quanto segue a 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

Il codice è preso da # 8009 .




Ho creato un pacchetto Python che risolve questo problema

https://github.com/brookisme/gitnb

Fornisce una CLI con una sintassi ispirata a git per tenere traccia / aggiornare / differenziare i taccuini all'interno del tuo repository git.

Ecco un esempio

# 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"

Nota che l'ultimo passaggio, dove sto usando "gitnb commit", sta per essere eseguito sul tuo repository git. È essenzialmente un involucro per

# 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"

Ci sono molti altri metodi, e possono essere configurati in modo che richieda più o meno input da parte dell'utente in ogni fase, ma questa è l'idea generale.




Ecco una nuova soluzione di Cyrille Rossant per IPython 3.0, che persiste nei file markdown piuttosto che nei file ipymd basati su json:

https://github.com/rossant/ipymd




Ho fatto quello che hanno fatto Albert & Rich - Non i file .ipynb della versione (in quanto possono contenere immagini, che diventano disordinate). Invece, esegui sempre ipython notebook --script o inserisci c.FileNotebookManager.save_script = True nel tuo file di configurazione, in modo che un file (versionable) .py venga sempre creato quando salvi il notebook.

Per rigenerare i taccuini (dopo aver controllato un repository o aver cambiato un ramo) inserisco lo script py_file_to_notebooks.py nella directory in cui memorizzo i miei taccuini.

Ora, dopo aver controllato un repository, esegui python py_file_to_notebooks.py per generare i file ipynb. Dopo aver cambiato ramo, potresti dover eseguire python py_file_to_notebooks.py -ov per sovrascrivere i file ipynb esistenti.

Giusto per essere sicuri, è bene aggiungere anche *.ipynb al file *.ipynb .

Modifica: Non lo faccio più perché (A) devi rigenerare i tuoi taccuini dai file py ogni volta che esegui il checkout di un ramo e (B) ci sono altre cose come il markdown nei taccuini che perdi. Io invece spoglio l'output dai notebook usando un filtro git. La discussione su come farlo è nbstripout.py .




Io uso un approccio molto pragmatico; che funzionano bene per diversi notebook, su più lati. E mi permette persino di "trasferire" i taccuini in giro. Funziona sia per Windows come Unix / MacOS.
Al pensato che sia semplice, è risolvere i problemi di cui sopra ...

Concetto

Fondamentalmente, non tracciare i file .ipnyb , solo i corrispondenti file .py .
Avviando il server notebook con l'opzione --script , quel file viene automaticamente creato / salvato quando il notebook viene salvato.

Quei file .py contengono tutto l'input; il non codice viene salvato nei commenti, così come i bordi della cella. Questi file possono essere letti / importati (e trascinati) nel server del notebook per (ri) creare un blocco note. Solo l'output è andato; finché non viene rieseguito.

Personalmente uso mercurial per la versione-track dei file .py ; e usa i normali comandi (da riga di comando) per aggiungere, check-in (ect) per quello. La maggior parte degli altri (D) VCS permetterà a questo.

È semplice tracciare la storia ora; le .py sono piccole, testuali e semplici da diff. Di tanto in tanto, abbiamo bisogno di un clone (solo un ramo, avviare un secondo notebook-sever lì), o una versione precedente (check-out e importazione in un notebook-server), ecc.

Consigli e trucchi

  • Aggiungi * .ipynb a ' .hgignore ', quindi Mercurial sa che può ignorare quei file
  • Crea uno script (bash) per avviare il server (con l'opzione --script ) ed --script versione-track it
  • Salvare un .py note salva il file .py , ma non lo controlla.
    • Questo è un inconveniente : uno può dimenticarlo
    • È anche una funzionalità : è possibile salvare un blocco note (e continuare in seguito) senza raggruppare la cronologia del repository.

Auguri

  • Sarebbe bello avere un pulsante per il check-in / aggiungere / etc nel Dashboard del notebook
  • Un checkout a (ad esempio) file@date+rev.py ) dovrebbe essere utile Sarebbe molto lavoro aggiungere questo; e forse lo farò una volta. Fino ad ora, lo faccio solo a mano.



Links