Menggunakan notebook IPython di bawah kontrol versi


569

Apa strategi yang baik untuk menjaga notebook IPython di bawah kendali versi?

Format notebook cukup setuju untuk kontrol versi: jika seseorang ingin mengontrol versi notebook dan output maka ini berfungsi dengan baik. Gangguan terjadi ketika seseorang hanya ingin versi mengontrol input, tidak termasuk output sel (alias. "Membangun produk") yang bisa menjadi gumpalan biner besar, terutama untuk film dan plot. Secara khusus, saya mencoba menemukan alur kerja yang baik yang:

  • memungkinkan saya untuk memilih antara termasuk atau tidak termasuk output,
  • mencegah saya dari sengaja melakukan output jika saya tidak menginginkannya,
  • memungkinkan saya untuk menyimpan hasil dalam versi lokal saya,
  • memungkinkan saya untuk melihat ketika saya memiliki perubahan dalam input menggunakan sistem kontrol versi saya (yaitu jika saya hanya versi mengontrol input tetapi file lokal saya memiliki output, maka saya ingin dapat melihat apakah input telah berubah (membutuhkan komit ). Menggunakan perintah status kontrol versi akan selalu mencatat perbedaan karena file lokal memiliki output.)
  • memungkinkan saya untuk memperbarui buku catatan kerja saya (yang berisi output) dari buku catatan bersih yang diperbarui. (memperbarui)

Seperti yang disebutkan, jika saya memilih untuk memasukkan output (yang diinginkan saat menggunakan nbviewer misalnya), maka semuanya baik-baik saja. Masalahnya adalah ketika saya tidak ingin versi mengontrol output. Ada beberapa alat dan skrip untuk melepaskan output notebook, tetapi seringkali saya menghadapi masalah berikut:

  1. Saya tidak sengaja melakukan versi dengan output, sehingga mencemari repositori saya.
  2. Saya menghapus output untuk menggunakan kontrol versi, tetapi lebih suka menyimpan output dalam salinan lokal saya (kadang-kadang butuh beberapa saat untuk mereproduksi misalnya).
  3. Beberapa skrip yang menghapus keluaran mengubah format sedikit dibandingkan dengan Cell/All Output/Clearopsi menu, sehingga menciptakan kebisingan yang tidak diinginkan di diffs. Ini diselesaikan dengan beberapa jawaban.
  4. Saat menarik perubahan ke versi file yang bersih, saya perlu menemukan beberapa cara untuk memasukkan perubahan itu di notebook saya yang bekerja tanpa harus menjalankan kembali semuanya. (memperbarui)

Saya telah mempertimbangkan beberapa opsi yang akan saya bahas di bawah, tetapi belum menemukan solusi komprehensif yang baik. Solusi lengkap mungkin memerlukan beberapa perubahan pada IPython, atau mungkin bergantung pada beberapa skrip eksternal sederhana. Saat ini saya menggunakan mercurial , tetapi ingin solusi yang juga berfungsi dengan git : solusi ideal adalah agnostik versi-kontrol.

Masalah ini telah dibahas berkali-kali, tetapi tidak ada solusi yang pasti atau jelas dari perspektif pengguna. Jawaban untuk pertanyaan ini harus memberikan strategi yang pasti. Tidak masalah jika memerlukan versi terbaru (bahkan pengembangan) dari IPython atau ekstensi yang mudah diinstal.

Pembaruan: Saya telah bermain dengan versi notebook saya yang dimodifikasi yang secara opsional menyimpan .cleanversi dengan setiap penyimpanan menggunakan saran Gregory Crosswhite . Ini memenuhi sebagian besar kendala saya tetapi membiarkan yang berikut ini tidak terselesaikan:

  1. Ini belum merupakan solusi standar (memerlukan modifikasi dari sumber ipython. Apakah ada cara untuk mencapai perilaku ini dengan ekstensi sederhana? Membutuhkan semacam pengait yang tersimpan.
  2. Masalah yang saya miliki dengan alur kerja saat ini adalah menarik perubahan. Ini akan masuk ke .cleanfile, dan kemudian perlu diintegrasikan entah bagaimana ke versi kerja saya. (Tentu saja, saya selalu dapat kembali menjalankan notebook, tetapi ini bisa menyebalkan, terutama jika beberapa hasil bergantung pada perhitungan panjang, perhitungan paralel, dll.) Saya belum memiliki ide bagus tentang bagaimana menyelesaikannya. . Mungkin alur kerja yang melibatkan ekstensi seperti ipycache mungkin berhasil, tetapi tampaknya agak terlalu rumit.

Catatan

Menghapus (stripping) Output

  • Saat notebook berjalan, seseorang dapat menggunakan Cell/All Output/Clearopsi menu untuk menghapus output.
  • Ada beberapa skrip untuk menghapus output, seperti skrip nbstripout.py yang menghapus output, tetapi tidak menghasilkan output yang sama seperti menggunakan antarmuka notebook. Ini akhirnya termasuk dalam repo ipython / nbconvert , tetapi ini telah ditutup menyatakan bahwa perubahan sekarang termasuk dalam ipython / ipython , tetapi fungsi yang sesuai tampaknya belum dimasukkan. (pemutakhiran) Yang dikatakan, solusi Gregory Crosswhite menunjukkan bahwa ini cukup mudah dilakukan, bahkan tanpa menggunakan ipython / nbconvert, jadi pendekatan ini mungkin bisa diterapkan jika dapat dihubungkan dengan benar. (Melampirkannya ke setiap sistem kontrol versi, bagaimanapun, sepertinya bukan ide yang bagus - ini entah bagaimana harus terhubung ke mekanisme notebook.)

Newsgroup

Masalah

Tarik Permintaan


Kedengarannya seperti hal yang hebat untuk ditambahkan sebagai masalah di github.com/ipython/ipython atau kirimkan permintaan tarik yang membantu Anda mencapai tujuan ini.
Kyle Kelley

4
Setelah Anda memiliki skrip yang berfungsi untuk menghapus output, Anda dapat menggunakan filter "bersih" Git untuk menerapkannya secara otomatis sebelum melakukan (lihat filter clean / smudge).
Matthias

1
@foobarbecue Pertanyaan ini berisi solusi yang tidak memuaskan: masing-masing memiliki setidaknya satu batasan. Sekarang PR 4175 telah digabungkan, solusi lengkap mungkin dapat dirumuskan, tetapi ini masih perlu dilakukan. Segera setelah saya punya waktu, saya akan melakukannya (sebagai jawaban) jika orang lain tidak memberikan solusi yang memuaskan sementara itu.
mforbes

1
@saroele Saya belum menemukan solusi yang disarankan: Saya akan pergi dengan --scriptopsi, tetapi itu telah dihapus. Saya menunggu sampai kait pasca-penyelamatan diimplementasikan ( yang direncanakan ) pada titik mana saya pikir saya akan dapat memberikan solusi yang dapat diterima menggabungkan beberapa teknik.
mforbes

1
@ mforbes Sepertinya PR baru saja bergabung beberapa hari setelah komentar Anda. Bisakah Anda atau seseorang yang lebih berpengetahuan daripada saya mengirim jawaban di sini yang menunjukkan cara menggunakan fitur baru?
KobeJohn

Jawaban:


124

Inilah solusi saya dengan git. Ini memungkinkan Anda untuk hanya menambahkan dan melakukan (seperti halnya diff) seperti biasa: operasi-operasi itu tidak akan mengubah pohon kerja Anda, dan pada saat yang sama menjalankan kembali notebook tidak akan mengubah riwayat git Anda.

Meskipun ini mungkin dapat diadaptasi ke VCS lain, saya tahu itu tidak memenuhi persyaratan Anda (setidaknya agnostisitas VSC). Tetap saja, itu sempurna untuk saya, dan meskipun tidak ada yang cemerlang, dan banyak orang mungkin sudah menggunakannya, saya tidak menemukan instruksi yang jelas tentang bagaimana menerapkannya dengan mencari-cari. Jadi semoga bermanfaat bagi orang lain.

  1. Simpan file dengan konten ini di suatu tempat (untuk yang berikut, mari kita asumsikan ~/bin/ipynb_output_filter.py)
  2. Jadikan itu dapat dieksekusi (chmod +x ~/bin/ipynb_output_filter.py )
  3. Buat file ~/.gitattributes, dengan konten berikut

    *.ipynb    filter=dropoutput_ipynb
    
  4. Jalankan perintah berikut:

    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
    

Selesai!

Keterbatasan:

  • ini hanya bekerja dengan git
  • di git, jika Anda berada di cabang somebranchdan Anda melakukannyagit checkout otherbranch; git checkout somebranch , Anda biasanya mengharapkan pohon yang bekerja tidak berubah. Di sini, alih-alih, Anda akan kehilangan output dan penomoran sel pada notebook yang sumbernya berbeda antara dua cabang.
  • lebih umum, output tidak diversi sama sekali, seperti dengan solusi Gregory. Agar tidak hanya membuangnya setiap kali Anda melakukan sesuatu yang melibatkan checkout, pendekatan tersebut dapat diubah dengan menyimpannya dalam file terpisah (tetapi perhatikan bahwa pada saat kode di atas dijalankan, komit id tidak diketahui!), dan mungkin versi mereka (tetapi perhatikan ini akan membutuhkan sesuatu yang lebih dari a git commit notebook_file.ipynb, meskipun setidaknya akan tetapgit diff notebook_file.ipynb terbebas dari sampah base64).
  • yang mengatakan, secara tidak sengaja jika Anda menarik kode (yaitu dilakukan oleh orang lain yang tidak menggunakan pendekatan ini) yang berisi beberapa output, output diperiksa secara normal. Hanya output yang diproduksi secara lokal yang hilang.

Solusi saya mencerminkan fakta bahwa saya pribadi tidak suka menyimpan versi yang dibuat berversi - perhatikan bahwa melakukan penggabungan yang melibatkan output hampir dijamin untuk membatalkan output atau produktivitas Anda atau keduanya.

EDIT:

  • jika Anda mengadopsi solusi seperti yang saya sarankan - yaitu, secara global - Anda akan memiliki masalah dalam kasus untuk beberapa repo git yang ingin Anda versi keluaran. Jadi jika Anda ingin menonaktifkan pemfilteran keluaran untuk repositori git tertentu, cukup buat di dalamnya file .git / info / atribut , dengan

    **. filter ipynb =

sebagai konten. Jelas, dengan cara yang sama dimungkinkan untuk melakukan yang sebaliknya: aktifkan penyaringan hanya untuk repositori tertentu.

  • kode ini sekarang disimpan dalam git repo sendiri

  • jika instruksi di atas menghasilkan ImportErrors, coba tambahkan "ipython" sebelum path script:

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

EDIT : Mei 2016 (diperbarui Februari 2017): ada beberapa alternatif untuk skrip saya - untuk kelengkapan, berikut adalah daftar yang saya tahu: nbstripout ( varian lain ), nbstrip , jq .


2
Bagaimana Anda menangani masalah memasukkan perubahan yang Anda tarik? Apakah Anda hanya hidup dengan harus meregenerasi semua output? (Saya pikir ini adalah perwujudan dari pembatasan kedua Anda.)
mforbes

1
@ zhermes: versi yang diperluas ini boleh-boleh saja
Pietro Battiston

1
Apakah ada cara untuk menggunakan metode filter git ini dengan alat diff eksternal? Filter diterapkan jika saya menggunakan alat baris perintah normal tetapi tidak jika saya menggunakan berbaur sebagai alat diff. stackoverflow.com/q/30329615/578770
FA

1
Untuk menghindari ImportErrorsaya harus mengubah cara di atas untuk menjalankan menggunakan ipython:git config --global filter.dropoutput_ipynb.clean ipython ~/bin/ipynb_output_filter.py
chris838

1
Awsome solusi Pietro, terima kasih :) Saya mengubah 2 hal ketika menggunakan script Anda dalam kasus saya: 1) Saya lebih suka menyatakan filter di .gitattributes di root repo sebagai lawan ~/.gitattributes, st orang lain memiliki filter yang sama seperti yang saya lakukan 2 ) Saya mendefinisikan regexp sebagai workdir/**/*.ipynb filter=dropoutput_ipynb, dan saya meletakkan sebagian besar notebook saya di workdir / => jika saya masih ingin mendorong notebook dengan output dan menikmati rendering bookmarkable di github, saya hanya meletakkannya di luar folder itu.
Svend

63

Kami memiliki proyek kolaborasi di mana produknya adalah Jupyter Notebooks, dan kami telah menggunakan pendekatan selama enam bulan terakhir yang berfungsi dengan baik: kami mengaktifkan menyimpan .pyfile secara otomatis dan melacak .ipynbfile dan .pyfile.

Dengan begitu jika seseorang ingin melihat / mengunduh buku catatan terbaru mereka dapat melakukannya melalui github atau nbviewer, dan jika seseorang ingin melihat bagaimana kode buku catatan telah berubah, mereka hanya dapat melihat perubahan pada .pyfile.

Untuk Jupyterserver notebook , ini dapat dilakukan dengan menambahkan baris

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

ke jupyter_notebook_config.pyfile dan me-restart server notebook.

Jika Anda tidak yakin di direktori mana untuk menemukan jupyter_notebook_config.pyfile Anda, Anda bisa mengetik jupyter --config-dir, dan jika Anda tidak menemukan file di sana, Anda dapat membuatnya dengan mengetik jupyter notebook --generate-config.

Untuk Ipython 3server notebook , ini dapat dilakukan dengan menambahkan baris

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

ke ipython_notebook_config.pyfile dan me-restart server notebook. Baris-baris ini berasal dari masalah github answer @minrk yang disediakan dan @dror memasukkannya dalam jawaban SO-nya juga.

Untuk Ipython 2server notebook , ini dapat dilakukan dengan memulai server menggunakan:

ipython notebook --script

atau dengan menambahkan baris

c.FileNotebookManager.save_script = True

ke ipython_notebook_config.pyfile dan me-restart server notebook.

Jika Anda tidak yakin di direktori mana untuk menemukan ipython_notebook_config.pyfile Anda, Anda bisa mengetik ipython locate profile default, dan jika Anda tidak menemukan file di sana, Anda dapat membuatnya dengan mengetik ipython profile create.

Inilah proyek kami di github yang menggunakan pendekatan ini : dan inilah contoh github untuk mengeksplorasi perubahan terbaru pada buku catatan .

Kami sangat senang dengan ini.


1
Terima kasih atas bukti tambahan bahwa menggunakan --scripttelah berhasil dalam praktik. Masalah dengan ini adalah bahwa notebook yang sebenarnya mungkin sangat besar jika gambar disimpan. Solusi ideal sepanjang jalan ini mungkin menggunakan sesuatu seperti git-lampiran untuk melacak hanya notebook penuh terbaru.
mforbes

Di Ipython 3.x --scripttidak digunakan lagi. ipython.org/ipython-doc/3/whatsnew/version3.html
Dror

Terima kasih @ teror, saya telah memperbarui jawaban saya untuk memberikan solusi ipython 3.x minrk seperti yang Anda berikan di sini.
Rich Signell

10
Pembaruan: Solusi ini rusak di iPython versi 4, karena "The Big Split" dari Jupyter dari iPython. Untuk menyesuaikan solusi ini ke versi 4, gunakan perintah jupyter notebook --generate-configuntuk membuat file konfigurasi. Perintah jupyter --config-dirmencari tahu direktori mana yang berisi file konfigurasi. Dan potongan kode yang diberikan oleh @Rich harus ditambahkan ke file bernama jupyter_notebook_config.py. Sisanya bekerja seperti sebelumnya.
Mobius dumpling

2
Selain titik dengan @mobiusdumpling, ganti check_call(['ipython'dengan check_call(['jupyter', jika tidak, Anda akan mendapatkan peringatan yang ipython nbconvertsudah usang dan Anda harus menggunakan jupyter nbconvertsebagai gantinya. (Jupyter v4.1.0, iPython v4.1.2)
cutculus

36

Saya telah membuat nbstripout, berdasarkan intisari MinRK , yang mendukung Git dan Mercurial (terima kasih kepada mforbes). Ini dimaksudkan untuk digunakan baik secara mandiri pada baris perintah atau sebagai filter, yang dengan mudah (tidak) dipasang di repositori saat ini melalui nbstripout install/ nbstripout uninstall.

Dapatkan dari PyPI atau cukup

pip install nbstripout

Saya sedang mempertimbangkan alur kerja tempat saya menyimpan .ipynb dan .py yang sesuai secara otomatis dibuat menggunakan kait pasca-penyimpanan yang dijelaskan di atas. Saya ingin menggunakan .py untuk diff - akan nbstripout dapat menghapus file .py dari penghitung eksekusi sel (# In [1] diubah menjadi In [*]), sehingga mereka tidak mengacaukan diff atau haruskah saya buat skrip sederhana untuk melakukan itu?
Krzysztof Słowiński

1
@ KrzysztofSłowiński Tidak, nbstripouttidak mendukung kasus penggunaan ini dengan mudah karena ini bergantung pada format JSON dari Notebook. Anda mungkin lebih baik menulis skrip yang khusus digunakan untuk kasus penggunaan Anda.
kynan


13

Setelah beberapa tahun menghapus output di notebook, saya telah mencoba mencari solusi yang lebih baik. Saya sekarang menggunakan Jupytext , ekstensi untuk Jupyter Notebook dan Jupyter Lab yang telah saya rancang.

Jupytext dapat mengonversi notebook Jupyter ke berbagai format teks (Script, Markdown, dan R Markdown). Dan sebaliknya. Ini juga menawarkan opsi untuk memasangkan notebook ke salah satu format ini, dan untuk secara otomatis menyinkronkan dua representasi notebook (an .ipynbdan .md/.py/.Rfile).

Biarkan saya menjelaskan bagaimana Jupytext menjawab pertanyaan di atas:

memungkinkan saya untuk memilih antara termasuk atau tidak termasuk output,

The .md/.py/.RFile hanya berisi sel masukan. Anda harus selalu melacak file ini. Versi .ipynbfile hanya jika Anda ingin melacak output.

mencegah saya dari sengaja melakukan output jika saya tidak menginginkannya,

Tambahkan *.ipynbke.gitignore

memungkinkan saya untuk menyimpan hasil dalam versi lokal saya,

Output yang diawetkan dalam (lokal) .ipynbFile

memungkinkan saya untuk melihat ketika saya memiliki perubahan dalam input menggunakan sistem kontrol versi saya (yaitu jika saya hanya versi mengontrol input tetapi file lokal saya memiliki output, maka saya ingin dapat melihat apakah input telah berubah (membutuhkan komit ). Menggunakan perintah status kontrol versi akan selalu mencatat perbedaan karena file lokal memiliki output.)

Diff pada .py/.Ratau .mdfile apa yang Anda cari

memungkinkan saya untuk memperbarui buku catatan kerja saya (yang berisi output) dari buku catatan bersih yang diperbarui. (memperbarui)

Tarik revisi .py/.Ratau .mdfile terbaru dan segarkan buku catatan Anda di Jupyter (Ctrl + R). Anda akan mendapatkan sel input terbaru dari file teks, dengan output yang cocok dari .ipynbfile tersebut. Kernel tidak terpengaruh, yang berarti bahwa variabel lokal Anda dipertahankan - Anda dapat melanjutkan bekerja di mana Anda meninggalkannya.

Yang saya sukai dari Jupytext adalah notebook tersebut (dalam bentuk file .py/.Ratau .md) dapat diedit di IDE favorit Anda. Dengan pendekatan ini, refactoring notebook menjadi mudah. Setelah selesai, Anda hanya perlu menyegarkan notebook di Jupyter.

Jika Anda ingin mencobanya: instal Jupytext dengan pip install jupytextdan restart Editor Jupyter atau Lab Anda. Buka buku catatan yang ingin Anda kontrol versi, dan pasangkan ke file Markdown (atau Script) menggunakan Menu Jupytext di notebook Jupyter (atau perintah Jupytext di Jupyter Lab). Simpan buku catatan Anda, dan Anda akan mendapatkan dua file: yang asli .ipynb, ditambah representasi teks yang dijanjikan dari buku catatan itu, yang sangat cocok untuk kontrol versi!

Bagi mereka yang mungkin tertarik: Jupytext juga tersedia di baris perintah .


13

Pembaruan : Sekarang Anda dapat mengedit file Notebook Jupyter langsung di Visual Studio Code. Anda dapat memilih untuk mengedit buku catatan atau file python yang dikonversi.

Saya akhirnya menemukan cara yang produktif dan sederhana untuk membuat Jupyter dan Git bermain bersama dengan baik. Saya masih dalam langkah pertama, tetapi saya sudah berpikir itu jauh lebih baik daripada semua solusi berbelit-belit lainnya.

Visual Studio Code adalah editor kode sumber yang keren dan terbuka dari Microsoft. Ini memiliki ekstensi Python yang sangat baik yang sekarang memungkinkan Anda untuk mengimpor Notebook Jupyter sebagai kode python. Sekarang Anda juga dapat langsung mengedit Notebook Jupyter .

Setelah Anda mengimpor buku catatan Anda ke file python, semua kode dan penurunan harga akan bersama-sama dalam file python biasa, dengan spidol khusus dalam komentar. Anda dapat melihat pada gambar di bawah ini:

Editor VSCode dengan notebook yang dikonversi menjadi python

File python Anda hanya memiliki isi sel input notebook. Output akan dihasilkan dalam jendela terpisah. Anda memiliki kode murni di notebook, itu tidak berubah saat Anda hanya menjalankannya. Tidak ada output yang berbaur dengan kode Anda. Tidak ada format JSON yang tidak dapat dipahami untuk menganalisis perbedaan Anda.

Hanya kode python murni di mana Anda dapat dengan mudah mengidentifikasi setiap perbedaan.

Saya bahkan tidak perlu membuat versi .ipynbfile saya lagi. Saya bisa meletakkan *.ipynbgaris di .gitignore.

Perlu membuat buku catatan untuk diterbitkan atau dibagikan dengan seseorang? Tidak masalah, cukup klik tombol ekspor di jendela python interaktif

Mengekspor file python ke format Notebook

Jika Anda mengedit buku catatan secara langsung, sekarang ada ikon Convert and save to a python script. Ikon Jupyter dalam Visual Studio Code

Berikut screenshot notebook di dalam Visual Studio Code:

Mengedit Notebook di dalam VSCode

Saya sudah menggunakannya hanya untuk sehari, tapi akhirnya saya bisa menggunakan Jupyter dengan Git.

PS: Penyelesaian kode VSCode jauh lebih baik daripada Jupyter.


12

(2017-02)

strategi

  • on_commit ():
    • lepaskan keluaran> name.ipynb ( nbstripout,)
    • lepaskan keluaran> name.clean.ipynb ( nbstripout,)
    • selalu nbconvertke python: name.ipynb.py ( nbconvert)
    • selalu konversikan ke penurunan harga: name.ipynb.md ( nbconvert, ipymd)
  • vcs.configure ():
    • git difftool, mergetool: nbdiff dan nbmerge dari nbdime

alat


11

Jawaban 2016 yang sangat populer di atas adalah peretasan yang tidak konsisten dibandingkan dengan cara yang lebih baik untuk melakukan ini pada 2019.

Ada beberapa opsi, yang terbaik untuk menjawab pertanyaan adalah Jupytext.

Jupytext

Tangkap artikel Menuju Ilmu Data di Jupytext

Cara kerjanya dengan kontrol versi adalah Anda meletakkan file .py dan .ipynb di kontrol versi. Lihatlah .py jika Anda menginginkan perbedaan input, lihat .ipynb jika Anda menginginkan hasil keluaran terbaru.

Menyebutkan menyebutkan: VS studio, nbconvert, nbdime, hidrogen

Saya pikir dengan sedikit lebih banyak pekerjaan, VS studio dan / atau hidrogen (atau yang serupa) akan menjadi pemain dominan dalam solusi untuk alur kerja ini.


9

Temukan "jupytext" yang terlihat seperti solusi sempurna. Ini menghasilkan file .py dari notebook dan kemudian membuat keduanya tetap sinkron. Anda dapat mengontrol versi, mengubah dan menggabungkan input melalui file .py tanpa kehilangan output. Ketika Anda membuka buku catatan itu menggunakan .py untuk sel input dan .ipynb untuk output. Dan jika Anda ingin memasukkan output di git maka Anda bisa menambahkan ipynb.

https://github.com/mwouts/jupytext


9

Karena terdapat begitu banyak strategi dan alat untuk menangani kontrol versi untuk notebook, saya mencoba membuat diagram alur untuk memilih strategi yang sesuai (dibuat April 2019)

Alur keputusan untuk memilih strategi kontrol versi


8

Seperti yang ditunjukkan oleh, yang --scriptsudah ditinggalkan di 3.x. Pendekatan ini dapat digunakan dengan menerapkan post-save-hook. Secara khusus, tambahkan yang berikut ini ke 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

Kode ini diambil dari # 8009 .


Terima kasih telah menunjukkan penggunaan kail pasca-simpan. Sayangnya, seperti yang disebutkan sebelumnya, kembali dari .pyfile ke notebook bermasalah, jadi ini sayangnya bukan solusi yang lengkap. (Saya agak berharap itu seperti itu sangat bagus untuk diff .pyfile daripada notebook. Mungkin fitur diff notebook baru akan berguna.
mforbes

1
Terima kasih! Saya sekarang menggunakan trik ini untuk mereproduksi --scriptperilaku, terlepas dari kontrol versi. Saya punya beberapa masalah pada awalnya, jadi kalau-kalau saya bisa menghemat waktu seseorang: 1) Jika ipython_notebook_config.pyada yang hilang dari folder profil, jalankan ipython profile createuntuk menghasilkannya. 2) Jika tampaknya post-save-hook diabaikan, jalankan ipython dengan --debuguntuk mendiagnosis masalah. 3) Jika script gagal dengan kesalahan ImportError: No module named mistune- instalasi sederhana minstue: pip install mistune.
Joe

7

Sayangnya, saya tidak tahu banyak tentang Mercurial, tetapi saya bisa memberi Anda solusi yang mungkin bekerja dengan Git, dengan harapan Anda mungkin bisa menerjemahkan perintah Git saya ke dalam padanan Mercurial mereka.

Untuk latar belakang, di Git addperintah menyimpan perubahan yang telah dibuat ke file ke area pementasan. Setelah Anda melakukan ini, setiap perubahan berikutnya pada file tersebut diabaikan oleh Git kecuali Anda memberi tahu untuk melakukan tahapan juga. Oleh karena itu, skrip berikut ini, yang, untuk masing-masing file yang diberikan, menghapus semua outputsdan prompt_number sections, tahapan file dilucuti, dan kemudian mengembalikan yang asli:

CATATAN: Jika menjalankan ini membuat Anda mendapatkan pesan kesalahan seperti ImportError: No module named IPython.nbformat, maka gunakan ipythonuntuk menjalankan skrip alih-alih 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)

Setelah skrip dijalankan pada file yang perubahannya ingin Anda komit, jalankan saja git commit.


Terima kasih untuk sarannya. Mercurial tidak benar-benar memiliki area pementasan seperti git (meskipun orang dapat menggunakan antrian mercurial untuk tujuan ini). Sementara itu, saya mencoba menambahkan kode ini ke save hook yang menyimpan versi bersih dengan .cleanekstensi. Sayangnya, saya tidak bisa melihat bagaimana melakukan ini tanpa secara langsung memodifikasi IPython (walaupun perubahan ini cukup sepele). Saya akan bermain dengan ini sebentar dan melihat apakah itu sesuai dengan semua kebutuhan saya.
mforbes

6

Saya menggunakan pendekatan yang sangat pragmatis; yang bekerja dengan baik untuk beberapa notebook, di beberapa sisi. Dan itu bahkan memungkinkan saya untuk 'mentransfer' notebook sekitar. Ini berfungsi baik untuk Windows sebagai Unix / MacOS.
Al pikir itu sederhana, adalah menyelesaikan masalah di atas ...

Konsep

Pada dasarnya, jangan tidak melacak .ipnyb-files, hanya yang sesuai .py-files.
Dengan memulai server notebook dengan --scriptopsi, file itu secara otomatis dibuat / disimpan ketika notebook disimpan.

Mereka .py-files memang mengandung semua masukan; non-kode disimpan ke dalam komentar, seperti halnya batas sel. File-file itu dapat dibaca / diimpor (dan diseret) ke dalam server notebook untuk membuat kembali notebook. Hanya output yang hilang; sampai dijalankan kembali.

Secara pribadi saya menggunakan lincah untuk melacak versi .pyfile; dan gunakan perintah normal (baris perintah) untuk menambahkan, check-in (dll) untuk itu. Kebanyakan VCS (D) lainnya akan mengizinkannya.

Sederhana untuk melacak sejarah sekarang; yang .pykecil, tekstual dan sederhana untuk diff. Sekali-sekali, kita perlu klon (hanya cabang; mulai notebook-2 ke sana), atau versi yang lebih lama (check-out dan impor ke server-notebook), dll.

Tips dan Trik

  • Tambahkan * .ipynb ke ' .hgignore ', sehingga Mercurial tahu ia dapat mengabaikan file-file itu
  • Buat skrip (bash) untuk memulai server (dengan --scriptopsi) dan lakukan lacak versi
  • Menyimpan notebook memang menyimpan file .py-file, tetapi tidak memeriksanya.
    • Ini adalah kelemahannya : Orang bisa melupakan itu
    • Ini adalah fitur juga: Mungkin untuk menyimpan buku catatan (dan melanjutkan nanti) tanpa mengelompokkan sejarah repositori.

Keinginan

  • Akan menyenangkan memiliki tombol untuk check-in / add / etc di Dashboard notebook
  • Checkout ke (dengan contoh) file@date+rev.py) harus membantu Akan banyak pekerjaan untuk menambahkan itu; dan mungkin saya akan melakukannya sekali. Sampai sekarang, saya hanya melakukannya dengan tangan.

Bagaimana Anda beralih dari .pyfile kembali ke buku catatan? Saya suka pendekatan ini, tetapi karena .ipynb-> .py-> .ipynbberpotensi lossy, saya tidak menganggap ini serius.
mforbes

Itu mudah: memuatnya, dengan menjatuhkannya di dasbor Notebook. Kecuali "data keluaran" tidak ada yang hilang
Albert

Jika itu benar, maka saya pikir ini akan dekat dengan ide, tetapi saya ingat bahwa IPython tidak membuat komitmen untuk sepenuhnya melestarikan data dalam transisi dari .pyke .ipynbformat. Ada masalah tentang ini - jadi mungkin ini akan menjadi dasar untuk solusi lengkap.
mforbes

Saya mengalami beberapa kesulitan mengkonversi dari .pyfile ke .ipynbfile. nbconvertsepertinya belum mendukung ini, dan saya tidak punya dashboard notebook karena saya berjalan ipython notebooksecara manual. Apakah Anda memiliki saran umum tentang cara menerapkan konversi mundur ini?
mforbes

Tentunya .pytransformasi ke notebook tidak dimaksudkan untuk pulang-pergi. Jadi ini tidak bisa menjadi solusi umum walaupun itu bagus untuk Anda.
holdenweb

3

Untuk menindaklanjuti skrip yang sangat baik oleh Pietro Battiston, jika Anda mendapatkan kesalahan penguraian Unicode seperti ini:

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)

Anda dapat menambahkan di awal skrip:

reload(sys)
sys.setdefaultencoding('utf8')

3

Saya telah membangun paket python yang memecahkan masalah ini

https://github.com/brookisme/gitnb

Ini memberikan CLI dengan sintaks yang diilhami git untuk melacak / memperbarui / membedakan notebook di dalam repo git Anda.

Inilah contohnya

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

Perhatikan bahwa langkah terakhir, di mana saya menggunakan "komit gitnb" berkomitmen untuk repo git Anda. Ini pada dasarnya pembungkus untuk

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

Ada beberapa metode lagi, dan dapat dikonfigurasi sehingga memerlukan input pengguna lebih atau kurang pada setiap tahap, tetapi itulah gagasan umum.


3

Setelah menggali sekitar, saya akhirnya menemukan kait pre-save relatif sederhana ini pada dokumen Jupyter . Itu strip data output sel. Anda harus menempelkannya ke jupyter_notebook_config.pyfile (lihat di bawah untuk petunjuk).

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

Dari jawaban Rich Signell :

Jika Anda tidak yakin di direktori mana untuk menemukan jupyter_notebook_config.pyfile Anda, Anda dapat mengetik jupyter --config-dir[ke command prompt / terminal], dan jika Anda tidak menemukan file di sana, Anda dapat membuatnya dengan mengetik jupyter notebook --generate-config.


1
Aku akan mencatat bahwa solusi ini tidak akan menyimpan setiap output ke disk, dan agak independen dari masalah kontrol versi.
bdforbes

2

Saya melakukan apa yang dilakukan oleh Albert & Rich - Jangan versi file .ipynb (karena ini dapat berisi gambar, yang menjadi berantakan). Sebagai gantinya, jalankan ipython notebook --scriptatau masukkan c.FileNotebookManager.save_script = Truefile konfigurasi Anda, sehingga file (versi) .pyselalu dibuat saat Anda menyimpan buku catatan.

Untuk membuat ulang buku catatan (setelah memeriksa repo atau mengganti cabang) saya meletakkan skrip py_file_to_notebooks.py di direktori tempat saya menyimpan buku catatan saya.

Sekarang, setelah memeriksa repo, jalankan saja python py_file_to_notebooks.pyuntuk menghasilkan file ipynb. Setelah berpindah cabang, Anda mungkin harus menjalankan python py_file_to_notebooks.py -ovuntuk menimpa file ipynb yang ada.

Hanya untuk berada di sisi aman, ada baiknya juga menambahkan *.ipynbke .gitignorefile Anda .

Sunting: Saya tidak lagi melakukan ini karena (A) Anda harus membuat ulang notebook Anda dari file py setiap kali Anda checkout cabang dan (B) ada hal-hal lain seperti penurunan harga di notebook yang Anda kehilangan. Saya malah menghapus output dari notebook menggunakan git filter. Diskusi tentang cara melakukan ini ada di sini .


Saya menyukai ide ini, tetapi setelah pengujian, menemukan bahwa konversi dari .pyfile kembali ke .ipynbbermasalah, terutama dengan notebook versi 4 yang belum ada konverter. Seseorang saat ini perlu menggunakan importir v3 kemudian mengonversi ke v4 dan saya agak khawatir tentang perjalanan yang rumit ini. Selain itu, .pyfile bukanlah pilihan yang sangat baik jika notebook itu terutama kode Julia! Akhirnya, --scriptsudah usang jadi saya pikir kait adalah cara untuk pergi.
mforbes

Solusi git filter di tautan Anda bagus, Anda harus menyalin jawaban Anda dari sini :-)
mcarans

2

Ok, jadi sepertinya solusi terbaik saat ini, sesuai diskusi di sini , adalah membuat git filter untuk secara otomatis menghapus output dari file ipynb di commit.

Inilah yang saya lakukan untuk membuatnya bekerja (disalin dari diskusi itu):

Saya memodifikasi file nbstripout cfriedline sedikit untuk memberikan kesalahan informatif ketika Anda tidak dapat mengimpor IPython terbaru: https://github.com/petered/plato/blob/fb2f4e252f50c79768920d0e47b870a8d799e92b/notebooks/config/strip untuk ditambahkan ke URL, lalu tambahkan ke url buku teks, lalu tambahkan ke URL saya, lalu tambahkan dengan url buku teks ke http: katakan dalam./relative/path/to/strip_notebook_output

Juga menambahkan file .gitattributes file ke root repo, berisi:

*.ipynb filter=stripoutput

Dan menciptakan yang setup_git_filters.shmengandung

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

Dan berlari source setup_git_filters.sh. Yang mewah $ (git rev-parse ...) masalahnya adalah menemukan jalur lokal repo Anda pada mesin (Unix) apa saja.


1

Ekstensi jupyter ini memungkinkan pengguna untuk mendorong notebook jupyter langsung ke github.

Silakan lihat di sini

https://github.com/sat28/githubcommit


dapatkah Anda menjelaskan apa yang dilakukannya? Dokumentasinya tidak terlalu jelas.
Alex Monras

@AlexMonras Ini akan langsung menambahkan tombol di jupyter notebook dari mana Anda dapat mendorong notebook ke repo GitHub Anda dengan pesan komit
sat

1

Ini April-2020 dan ada banyak strategi dan alat untuk kontrol versi notebook Jupyter. Berikut ini ikhtisar singkat dari semua alat yang dapat Anda gunakan,

  • nbdime - Bagus untuk diff'ing lokal dan penggabungan notebook

  • nbstripout - Filter git untuk secara otomatis menghapus output notebook sebelum setiap commit

  • jupytext - Menyimpan file pendamping .py ke setiap buku catatan. Anda hanya melakukan file .py

  • nbconvert - Konversi buku catatan menjadi skrip python atau HTML (atau keduanya) dan lakukan jenis file alternatif ini

  • ReviewNB - Menampilkan perbedaan notebook (bersama dengan output) untuk setiap komit atau permintaan tarik pada GitHub. Anda juga dapat menulis komentar pada sel buku catatan untuk membahas perubahan (tangkapan layar di bawah).

masukkan deskripsi gambar di sini

Penafian: Saya membangun ReviewNB.


0

Bagaimana dengan ide yang dibahas dalam posting di bawah ini, di mana output notebook harus disimpan, dengan argumen bahwa mungkin diperlukan waktu lama untuk menghasilkannya, dan ini berguna karena GitHub sekarang dapat membuat notebook. Ada kait simpan otomatis yang ditambahkan untuk mengekspor file .py, digunakan untuk diffs dan .html untuk berbagi dengan anggota tim yang tidak menggunakan buku catatan atau git.

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.