Sử dụng máy tính xách tay IPython dưới sự kiểm soát phiên bản


569

Một chiến lược tốt để giữ máy tính xách tay IPython dưới sự kiểm soát phiên bản là gì?

Định dạng máy tính xách tay khá phù hợp với kiểm soát phiên bản: nếu một người muốn phiên bản kiểm soát máy tính xách tay và các đầu ra thì điều này hoạt động khá tốt. Sự khó chịu xuất hiện khi người ta chỉ muốn phiên bản kiểm soát đầu vào, ngoại trừ đầu ra ô (hay còn gọi là "sản phẩm xây dựng") có thể là các đốm nhị phân lớn, đặc biệt là cho phim và cốt truyện. Cụ thể, tôi đang cố gắng tìm một quy trình làm việc tốt:

  • cho phép tôi chọn giữa bao gồm hoặc loại trừ đầu ra,
  • ngăn tôi vô tình cam kết đầu ra nếu tôi không muốn nó,
  • cho phép tôi giữ đầu ra trong phiên bản địa phương của tôi,
  • cho phép tôi xem khi nào tôi có thay đổi trong đầu vào bằng hệ thống kiểm soát phiên bản của mình (nghĩa là nếu tôi chỉ kiểm soát phiên bản đầu vào nhưng tệp cục bộ của tôi có đầu ra, thì tôi muốn xem liệu đầu vào có thay đổi không (yêu cầu cam kết ). Sử dụng lệnh trạng thái kiểm soát phiên bản sẽ luôn đăng ký chênh lệch do tệp cục bộ có đầu ra.)
  • cho phép tôi cập nhật sổ ghi chép làm việc của mình (có chứa đầu ra) từ sổ ghi chép sạch được cập nhật. (cập nhật)

Như đã đề cập, nếu tôi chọn bao gồm các kết quả đầu ra (điều mong muốn khi sử dụng nbviewer chẳng hạn), thì mọi thứ đều ổn. Vấn đề là khi tôi không muốn phiên bản kiểm soát đầu ra. Có một số công cụ và tập lệnh để tước đầu ra của sổ ghi chép, nhưng tôi thường gặp phải các vấn đề sau:

  1. Tôi vô tình cam kết một phiên bản với đầu ra, do đó làm ô nhiễm kho lưu trữ của tôi.
  2. Tôi xóa đầu ra để sử dụng kiểm soát phiên bản, nhưng thực sự sẽ giữ đầu ra trong bản sao cục bộ của tôi (đôi khi phải mất một thời gian để sao chép chẳng hạn).
  3. Một số tập lệnh dải đầu ra thay đổi định dạng một chút so với Cell/All Output/Cleartùy chọn menu, do đó tạo ra tiếng ồn không mong muốn trong các khác biệt. Điều này được giải quyết bằng một số câu trả lời.
  4. Khi kéo các thay đổi sang phiên bản sạch của tệp, tôi cần tìm một số cách kết hợp những thay đổi đó trong sổ ghi chép làm việc của mình mà không phải chạy lại mọi thứ. (cập nhật)

Tôi đã xem xét một số tùy chọn mà tôi sẽ thảo luận dưới đây, nhưng vẫn chưa tìm thấy một giải pháp toàn diện tốt. Một giải pháp đầy đủ có thể yêu cầu một số thay đổi đối với IPython hoặc có thể dựa vào một số tập lệnh bên ngoài đơn giản. Tôi hiện đang sử dụng đồng bóng , nhưng muốn một giải pháp cũng hoạt động với git : một giải pháp lý tưởng sẽ là thuyết bất khả tri kiểm soát phiên bản.

Vấn đề này đã được thảo luận nhiều lần, nhưng không có giải pháp rõ ràng hoặc rõ ràng từ quan điểm của người dùng. Câu trả lời cho câu hỏi này sẽ cung cấp chiến lược dứt khoát. Sẽ ổn nếu nó yêu cầu một phiên bản (thậm chí phát triển) gần đây của IPython hoặc một phần mở rộng dễ cài đặt.

Cập nhật: Tôi đã chơi với phiên bản máy tính xách tay đã sửa đổi của mình , tùy chọn lưu .cleanphiên bản với mỗi lần lưu bằng các đề xuất của Gregory Crosswhite . Điều này đáp ứng hầu hết các ràng buộc của tôi nhưng không giải quyết được những điều sau đây:

  1. Đây chưa phải là một giải pháp tiêu chuẩn (yêu cầu sửa đổi nguồn ipython. Có cách nào để đạt được hành vi này với một phần mở rộng đơn giản không? Cần một số loại móc lưu.
  2. Một vấn đề tôi gặp phải với quy trình làm việc hiện tại là kéo theo những thay đổi. Những thứ này sẽ đến.clean tập tin và sau đó cần được tích hợp vào phiên bản làm việc của tôi. (Tất nhiên, tôi luôn có thể thực hiện lại sổ ghi chép, nhưng điều này có thể gây khó khăn, đặc biệt là nếu một số kết quả phụ thuộc vào tính toán dài, tính toán song song, v.v.) Tôi không biết cách giải quyết vấn đề này . Có lẽ một quy trình công việc liên quan đến một phần mở rộng như ipycache có thể hoạt động, nhưng điều đó có vẻ hơi phức tạp.

Ghi chú

Loại bỏ (tước) đầu ra

  • Khi máy tính xách tay đang chạy, người ta có thể sử dụng Cell/All Output/Clear tùy chọn menu để loại bỏ đầu ra.
  • Có một số tập lệnh để loại bỏ đầu ra, chẳng hạn như tập lệnh nbstripout.py loại bỏ đầu ra, nhưng không tạo ra đầu ra giống như sử dụng giao diện máy tính xách tay. Điều này cuối cùng đã được bao gồm trong repo ipython / nbconvert , nhưng điều này đã được đóng lại nói rằng những thay đổi hiện được bao gồm trong ipython / ipython , nhưng chức năng tương ứng dường như chưa được đưa vào. (cập nhật) Điều đó đang được nói, giải pháp của Gregory Crosswhite cho thấy điều này khá dễ thực hiện, ngay cả khi không gọi ipython / nbconvert, vì vậy cách tiếp cận này có thể khả thi nếu nó có thể được nối đúng cách.

Nhóm tin

Các vấn đề

Yêu cầu kéo


Nghe có vẻ như là một điều tuyệt vời để thêm vào như một vấn đề trên github.com/ipython/ipython hoặc gửi yêu cầu kéo giúp bạn tiếp tục mục tiêu này.
Kyle Kelley

4
Khi bạn có tập lệnh hoạt động để xóa đầu ra, bạn có thể sử dụng bộ lọc "sạch" Git để tự động áp dụng nó trước khi cam kết (xem bộ lọc sạch / nhòe).
Matthias

1
@foobarbiru Câu hỏi chứa cách giải quyết không thỏa đáng: mỗi câu hỏi có ít nhất một giới hạn. Bây giờ PR 4175 đã được hợp nhất, một giải pháp hoàn chỉnh có thể được đưa ra, nhưng điều này vẫn cần phải được thực hiện. Ngay khi tôi có thời gian, tôi sẽ làm điều đó (như một câu trả lời) nếu người khác không cung cấp giải pháp thỏa đáng trong lúc này.
mforbes

1
@saroele Tôi chưa tìm thấy giải pháp được đề xuất: Tôi sẽ đi với --scripttùy chọn, nhưng nó đã bị xóa. Tôi đang đợi cho đến khi các móc hậu lưu được triển khai ( đã được lên kế hoạch ) tại thời điểm đó tôi nghĩ rằng tôi sẽ có thể cung cấp một giải pháp chấp nhận được kết hợp một số kỹ thuật.
mforbes

1
@mforbes Hình như PR đó mới được hợp nhất vài ngày sau bình luận của bạn. Bạn có thể hoặc ai đó hiểu biết hơn tôi gửi câu trả lời ở đây chỉ ra cách sử dụng tính năng mới không?
KobeJohn 17/12/14

Câu trả lời:


124

Đây là giải pháp của tôi với git. Nó cho phép bạn chỉ cần thêm và cam kết (và khác biệt) như bình thường: các hoạt động đó sẽ không làm thay đổi cây làm việc của bạn, đồng thời (chạy lại) một máy tính xách tay sẽ không làm thay đổi lịch sử git của bạn.

Mặc dù điều này có thể phù hợp với các VCS khác, tôi biết nó không đáp ứng yêu cầu của bạn (ít nhất là tính bất khả tri của VSC). Tuy nhiên, nó là hoàn hảo đối với tôi, và mặc dù nó không có gì đặc biệt, và nhiều người có thể đã sử dụng nó, tôi đã không tìm thấy hướng dẫn rõ ràng về cách thực hiện nó bằng cách đi vòng quanh. Vì vậy, nó có thể hữu ích cho những người khác.

  1. Lưu một tệp có nội dung này ở đâu đó (đối với phần sau, chúng ta hãy giả sử ~/bin/ipynb_output_filter.py)
  2. Làm cho nó thực thi ( chmod +x ~/bin/ipynb_output_filter.py)
  3. Tạo tập tin ~/.gitattributes, với nội dung sau

    *.ipynb    filter=dropoutput_ipynb
    
  4. Chạy các lệnh sau:

    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
    

Làm xong!

Hạn chế:

  • nó chỉ hoạt động với git
  • trong git, nếu bạn ở trong nhánh somebranchvà bạn làm git checkout otherbranch; git checkout somebranch, bạn thường mong đợi cây làm việc không thay đổi. Ở đây, thay vào đó bạn sẽ mất đầu ra và đánh số ô của sổ ghi chép có nguồn khác nhau giữa hai nhánh.
  • nói chung, đầu ra hoàn toàn không được phiên bản, như với giải pháp của Gregory. Để không chỉ vứt nó đi mỗi khi bạn làm bất cứ điều gì liên quan đến thanh toán, cách tiếp cận có thể được thay đổi bằng cách lưu trữ nó trong các tệp riêng biệt (nhưng lưu ý rằng tại thời điểm mã trên được chạy, id xác nhận không được biết!), và có thể phiên bản chúng (nhưng chú ý điều này sẽ đòi hỏi nhiều hơn một git commit notebook_file.ipynb, mặc dù ít nhất nó sẽ giữgit diff notebook_file.ipynb rác cơ sở64).
  • điều đó nói rằng, tình cờ nếu bạn thực hiện mã kéo (nghĩa là được cam kết bởi người khác không sử dụng phương pháp này) có chứa một số đầu ra, đầu ra được kiểm tra bình thường. Chỉ có sản lượng sản xuất tại địa phương bị mất.

Giải pháp của tôi phản ánh thực tế rằng cá nhân tôi không muốn giữ phiên bản được tạo theo phiên bản - lưu ý rằng việc thực hiện hợp nhất liên quan đến đầu ra gần như được đảm bảo để vô hiệu hóa đầu ra hoặc năng suất của bạn hoặc cả hai.

BIÊN TẬP:

  • nếu bạn áp dụng giải pháp như tôi đã đề xuất - nghĩa là trên toàn cầu - bạn sẽ gặp rắc rối trong trường hợp đối với một số repo git mà bạn muốn phiên bản đầu ra. Vì vậy, nếu bạn muốn tắt tính năng lọc đầu ra cho kho lưu trữ git cụ thể, chỉ cần tạo bên trong tệp một tệp .git / thông tin / thuộc tính , với

    **. Bộ lọc ipynb =

như nội dung. Rõ ràng, trong cùng một cách có thể làm ngược lại: cho phép lọc chỉ cho một kho lưu trữ cụ thể.

  • mã hiện được duy trì trong repo git riêng của nó

  • nếu các hướng dẫn ở trên dẫn đến ImportErrors, hãy thử thêm "ipython" trước đường dẫn của tập lệnh:

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

EDIT : Tháng 5 năm 2016 (cập nhật tháng 2 năm 2017): có một số lựa chọn thay thế cho kịch bản của tôi - để hoàn thiện, đây là danh sách những người tôi biết: nbstripout ( các biến thể khác ), nbstrip , jq .


2
Làm thế nào để bạn đối phó với vấn đề kết hợp những thay đổi mà bạn kéo? Bạn chỉ sống với việc phải tạo lại tất cả đầu ra? (Tôi nghĩ rằng đây là biểu hiện của giới hạn thứ hai của bạn.)
mforbes

1
@zhermes: phiên bản mở rộng này sẽ ổn thôi
Pietro Battiston

1
Có cách nào để sử dụng phương pháp bộ lọc git này với một công cụ tìm khác biệt bên ngoài không? Bộ lọc được áp dụng nếu tôi sử dụng công cụ dòng lệnh thông thường nhưng không sử dụng nếu tôi sử dụng meld làm công cụ tìm khác biệt. stackoverflow.com/q/30329615/578770
FA

1
Để tránh bị bắt, ImportErrortôi đã thay đổi cách trên để chạy bằng ipython:git config --global filter.dropoutput_ipynb.clean ipython ~/bin/ipynb_output_filter.py
chris838

1
Giải pháp tuyệt vời Pietro, cảm ơn :) Tôi đã thay đổi 2 điều khi sử dụng tập lệnh của bạn trong trường hợp của tôi: 1) Tôi thích khai báo bộ lọc trong .gitattribut trong thư mục gốc của repo chứ không phải ~/.gitattributesngười khác có cùng bộ lọc như tôi 2 ) Tôi đã xác định regrec là workdir/**/*.ipynb filter=dropoutput_ipynbvà tôi đặt hầu hết các notebook của mình vào workdir / => nếu tôi vẫn muốn đẩy một notebook với đầu ra và thưởng thức kết xuất có thể đánh dấu trong github, tôi chỉ cần đặt nó bên ngoài thư mục đó.
Svend

63

Chúng tôi có một dự án hợp tác trong đó sản phẩm là Jupyter Notebooks và chúng tôi đã sử dụng một phương pháp trong sáu tháng qua đang hoạt động rất tốt: chúng tôi kích hoạt lưu .pytệp tự động và theo dõi cả .ipynbtệp và .pytệp.

Theo cách đó, nếu ai đó muốn xem / tải xuống sổ ghi chép mới nhất, họ có thể thực hiện điều đó thông qua github hoặc nbviewer và nếu ai đó muốn xem mã sổ ghi chép đã thay đổi như thế nào, họ có thể xem xét các thay đổi của .pytệp.

Đối với Jupytermáy chủ máy tính xách tay , điều này có thể được thực hiện bằng cách thêm các dòng

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

vào jupyter_notebook_config.pytập tin và khởi động lại máy chủ notebook.

Nếu bạn không chắc chắn trong thư mục nào sẽ tìm thấy jupyter_notebook_config.pytệp của mình , bạn có thể nhập jupyter --config-dirvà nếu bạn không tìm thấy tệp ở đó, bạn có thể tạo tệp đó bằng cách nhập jupyter notebook --generate-config.

Đối với Ipython 3máy chủ máy tính xách tay , điều này có thể được thực hiện bằng cách thêm các dòng

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

vào ipython_notebook_config.pytập tin và khởi động lại máy chủ notebook. Những dòng này là từ một vấn đề github trả lời @minrk cung cấp và @dror bao gồm chúng trong câu trả lời SO của anh ấy.

Đối với Ipython 2máy chủ máy tính xách tay , điều này có thể được thực hiện bằng cách khởi động máy chủ bằng cách sử dụng:

ipython notebook --script

hoặc bằng cách thêm dòng

c.FileNotebookManager.save_script = True

vào ipython_notebook_config.pytập tin và khởi động lại máy chủ notebook.

Nếu bạn không chắc chắn trong thư mục nào sẽ tìm thấy ipython_notebook_config.pytệp của mình , bạn có thể nhập ipython locate profile defaultvà nếu bạn không tìm thấy tệp ở đó, bạn có thể tạo tệp đó bằng cách nhập ipython profile create.

Đây là dự án của chúng tôi trên github đang sử dụng phương pháp này : và đây là một ví dụ github về khám phá những thay đổi gần đây cho một cuốn sổ tay .

Chúng tôi đã rất hạnh phúc với điều này.


1
Cảm ơn các bằng chứng bổ sung rằng sử dụng --scriptđã làm việc trong thực tế. Vấn đề với điều này là các máy tính xách tay thực tế có thể rất lớn nếu hình ảnh được lưu giữ. Một giải pháp lý tưởng theo cách này có thể sử dụng một cái gì đó như git-annex để chỉ theo dõi sổ ghi chép đầy đủ mới nhất.
mforbes

Trong Ipython 3.x --scriptthì không được dùng nữa. ipython.org/ipython-doc/3/whatsnew/version3.html
Dror

Cảm ơn @dror, tôi đã cập nhật câu trả lời của mình để cung cấp giải pháp ipython 3.x của minrk như bạn cũng đã cung cấp ở đây.
Rich Signell 13/03/2015

10
Cập nhật: Giải pháp này đã bị hỏng trong iPython phiên bản 4, do "The Big Split" của Jupyter từ iPython. Để điều chỉnh giải pháp này cho phiên bản 4, sử dụng lệnh jupyter notebook --generate-configđể tạo tệp cấu hình. Lệnh jupyter --config-dirtìm ra thư mục nào chứa các tệp cấu hình. Và đoạn mã được cung cấp bởi @Rich nên được thêm vào tệp có tên jupyter_notebook_config.py. Phần còn lại hoạt động như trước.
bánh bao mobius

2
Ngoài điểm bởi @mobiusdumpling, hãy thay thế check_call(['ipython'bằng check_call(['jupyter', nếu không bạn sẽ nhận được cảnh báo không ipython nbconvertđược chấp nhận và jupyter nbconvertthay vào đó bạn nên sử dụng . (Jupyter v4.1.0, iPython v4.1.2)
cutculus

36

Tôi đã tạo ra nbstripout, dựa trên ý chính của MinRK , hỗ trợ cả Git và Mercurial (nhờ mforbes). Nó được dự định sẽ được sử dụng độc lập trên dòng lệnh hoặc như một bộ lọc, dễ dàng (un) được cài đặt trong kho lưu trữ hiện tại thông qua nbstripout install/ nbstripout uninstall.

Nhận nó từ PyPI hoặc đơn giản là

pip install nbstripout

Tôi đang xem xét một quy trình làm việc trong đó tôi giữ cả .ipynb và .py tương ứng được tạo tự động bằng cách sử dụng các móc hậu lưu được mô tả ở trên. Tôi muốn sử dụng .py cho diffs - nbstripout có thể xóa tệp .py khỏi bộ đếm thực thi ô (# In [1] đã đổi thành In [*]), để chúng không làm lộn xộn các khác biệt hay tôi nên tạo một kịch bản đơn giản để làm điều đó?
Krzysztof Słowiński

1
@ KrzysztofSłowiński Không, nbstripoutkhông hỗ trợ trường hợp sử dụng này một cách dễ dàng vì nó phụ thuộc vào định dạng JSON của Notebook. Bạn có thể tốt hơn nên viết một tập lệnh chuyên biệt cho trường hợp sử dụng của bạn.
kynan

13

Đây là một giải pháp mới từ Cyrille Rossant cho IPython 3.0, vẫn tồn tại để đánh dấu các tệp thay vì các tệp ipymd dựa trên json:

https://github.com/rossant/ipymd


Không hỗ trợ Jupyter, có vẻ như.
K.-Michael Aye

Tôi đang sử dụng ipymd thành công với Jupyter mới nhất - bạn có nhận được bất kỳ vấn đề cụ thể hoặc thông báo lỗi nào không?
Cyrille Rossant

13

Sau một vài năm loại bỏ đầu ra trong máy tính xách tay, tôi đã cố gắng đưa ra một giải pháp tốt hơn. Bây giờ tôi sử dụng Jupytext , một phần mở rộng cho cả Jupyter Notebook và Jupyter Lab mà tôi đã thiết kế.

Jupytext có thể chuyển đổi sổ ghi chép Jupyter sang các định dạng văn bản khác nhau (ScScript, Markdown và R Markdown). Và ngược lại. Nó cũng cung cấp tùy chọn ghép nối một sổ ghi chép với một trong các định dạng này và để tự động đồng bộ hóa hai biểu diễn của sổ ghi chép (một .ipynbvà một .md/.py/.Rtệp).

Hãy để tôi giải thích cách Jupytext trả lời các câu hỏi trên:

cho phép tôi chọn giữa bao gồm hoặc loại trừ đầu ra,

Các .md/.py/.Rtập tin chỉ chứa các ô đầu vào. Bạn nên luôn luôn theo dõi tập tin này. Phiên bản .ipynbtệp chỉ khi bạn muốn theo dõi đầu ra.

ngăn tôi vô tình cam kết đầu ra nếu tôi không muốn nó,

Thêm *.ipynbvào.gitignore

cho phép tôi giữ đầu ra trong phiên bản địa phương của tôi,

Đầu ra được bảo toàn trong .ipynbtệp (cục bộ)

cho phép tôi xem khi nào tôi có thay đổi trong đầu vào bằng hệ thống kiểm soát phiên bản của mình (nghĩa là nếu tôi chỉ kiểm soát phiên bản đầu vào nhưng tệp cục bộ của tôi có đầu ra, thì tôi muốn xem liệu đầu vào có thay đổi không (yêu cầu cam kết ). Sử dụng lệnh trạng thái kiểm soát phiên bản sẽ luôn đăng ký chênh lệch do tệp cục bộ có đầu ra.)

Khác biệt trên .py/.Rhoặc .mdtập tin là những gì bạn đang tìm kiếm

cho phép tôi cập nhật sổ ghi chép làm việc của mình (có chứa đầu ra) từ sổ ghi chép sạch được cập nhật. (cập nhật)

Kéo bản sửa đổi mới nhất của tệp .py/.Rhoặc .mdtệp và làm mới sổ ghi chép của bạn trong Jupyter (Ctrl + R). Bạn sẽ nhận được các ô nhập mới nhất từ ​​tệp văn bản, với các đầu ra khớp từ .ipynbtệp. Hạt nhân không bị ảnh hưởng, điều đó có nghĩa là các biến cục bộ của bạn được bảo tồn - bạn có thể tiếp tục làm việc ở nơi bạn để nó.

Điều tôi thích với Jupytext là sổ ghi chép (dưới dạng tệp .py/.Rhoặc .mdtệp) có thể được chỉnh sửa trong IDE yêu thích của bạn. Với phương pháp này, việc tái cấu trúc một cuốn sổ tay trở nên dễ dàng. Khi bạn đã hoàn tất, bạn chỉ cần làm mới sổ ghi chép trong Jupyter.

Nếu bạn muốn dùng thử: cài đặt Jupytext pip install jupytextvà khởi động lại trình soạn thảo Jupyter Notebook hoặc Lab của bạn. Mở sổ ghi chép mà bạn muốn kiểm soát phiên bản và ghép nối nó với tệp Markdown (hoặc Tập lệnh) bằng Menu Jupytext trong sổ ghi chép Jupyter (hoặc các lệnh Jupytext trong Phòng thí nghiệm Jupyter). Lưu sổ ghi chép của bạn và bạn sẽ nhận được hai tệp: bản gốc .ipynb, cộng với bản trình bày văn bản đã hứa của sổ ghi chép, đó là một sự phù hợp hoàn hảo để kiểm soát phiên bản!

Đối với những người có thể quan tâm: Jupytext cũng có sẵn trên dòng lệnh .


13

Cập nhật : Bây giờ bạn có thể chỉnh sửa các tập tin Jupyter Notebook trực tiếp trong Visual Studio Code. Bạn có thể chọn chỉnh sửa sổ ghi chép hoặc tệp python đã chuyển đổi.

Cuối cùng tôi đã tìm thấy một cách hiệu quả và đơn giản để làm cho Jupyter và Git chơi thân với nhau. Tôi vẫn đang ở những bước đầu tiên, nhưng tôi đã nghĩ rằng nó tốt hơn rất nhiều so với tất cả các giải pháp phức tạp khác.

Visual Studio Code là một trình soạn thảo mã nguồn mở và thú vị của Microsoft. Nó có một tiện ích mở rộng Python tuyệt vời hiện cho phép bạn nhập Notebook Jupyter dưới dạng mã python. Bây giờ bạn cũng có thể trực tiếp chỉnh sửa Notebook Jupyter .

Sau khi bạn nhập sổ ghi chép của mình vào tệp python, tất cả mã và đánh dấu sẽ nằm cùng nhau trong một tệp python thông thường, với các dấu hiệu đặc biệt trong các bình luận. Bạn có thể thấy trong hình dưới đây:

Trình chỉnh sửa VSCode với một máy tính xách tay được chuyển đổi thành python

Tệp python của bạn chỉ có nội dung của các ô nhập sổ ghi chép. Đầu ra sẽ được tạo ra trong một cửa sổ chia. Bạn có mã thuần trong sổ ghi chép, nó không thay đổi trong khi bạn chỉ thực thi nó. Không có đầu ra trộn lẫn với mã của bạn. Không có định dạng JSON khó hiểu để phân tích khác biệt của bạn.

Chỉ cần mã python thuần, nơi bạn có thể dễ dàng xác định mỗi khác biệt.

Tôi thậm chí không cần phải phiên bản .ipynbcác tập tin của tôi nữa. Tôi có thể đặt một *.ipynbdòng trong .gitignore.

Cần tạo một máy tính xách tay để xuất bản hoặc chia sẻ với ai đó? Không có vấn đề, chỉ cần nhấp vào nút xuất trong cửa sổ python tương tác

Xuất tệp python sang định dạng Notebook

Nếu bạn đang chỉnh sửa sổ ghi chép trực tiếp, giờ đây đã có biểu tượng Convert and save to a python script. Biểu tượng Jupyter trong Visual Studio Code

Dưới đây là một ảnh chụp màn hình của một máy tính xách tay bên trong Visual Studio Code:

Chỉnh sửa Notebook bên trong VSCode

Tôi đã sử dụng nó chỉ trong một ngày, nhưng cuối cùng tôi cũng có thể vui vẻ sử dụng Jupyter với Git.

PS: Hoàn thành mã VSCode tốt hơn Jupyter rất nhiều.


12

(2017/02)

chiến lược

  • on_commit ():
    • tước đầu ra> name.ipynb ( nbstripout,)
    • tước đầu ra> name.clean.ipynb ( nbstripout,)
    • luôn luôn nbconvertđể python: name.ipynb.py ( nbconvert)
    • luôn chuyển đổi sang markdown: name.ipynb.md ( nbconvert, ipymd)
  • vcs. thông minh ():
    • git Difftool, mergetool: nbdiff và nbmerge từ nbdime

công cụ


11

Các câu trả lời năm 2016 rất phổ biến ở trên là những bản hack không nhất quán so với cách tốt hơn để làm điều này trong năm 2019.

Một số tùy chọn tồn tại, tốt nhất trả lời câu hỏi là Jupytext.

Jupytext

Theo dõi bài viết Khoa học dữ liệu về Jupytext

Cách thức hoạt động với kiểm soát phiên bản là bạn đặt cả tệp .py và .ipynb trong kiểm soát phiên bản. Nhìn vào .py nếu bạn muốn khác biệt đầu vào, hãy xem .ipynb nếu bạn muốn đầu ra được hiển thị mới nhất.

Đề cập đáng chú ý: VS studio, nbconvert, nbdime, hydro

Tôi nghĩ rằng với một chút công việc, VS studio và / hoặc hydro (hoặc tương tự) sẽ trở thành những người chơi thống trị trong giải pháp cho quy trình công việc này.


9

Chỉ cần đi qua "jupytext" trông giống như một giải pháp hoàn hảo. Nó tạo ra một tệp .py từ sổ ghi chép và sau đó giữ cả hai đồng bộ. Bạn có thể kiểm soát phiên bản, tìm khác biệt và hợp nhất các đầu vào thông qua tệp .py mà không mất các đầu ra. Khi bạn mở sổ ghi chép, nó sử dụng .py cho các ô nhập và .ipynb cho đầu ra. Và nếu bạn muốn bao gồm đầu ra trong git thì bạn chỉ cần thêm ipynb.

https://github.com/mwouts/jupytext


9

Vì tồn tại rất nhiều chiến lược và công cụ để xử lý kiểm soát phiên bản cho máy tính xách tay, tôi đã cố gắng tạo sơ đồ luồng để chọn một chiến lược phù hợp (được tạo vào tháng 4 năm 2019)

Luồng quyết định chọn chiến lược kiểm soát phiên bản


8

Như được chỉ ra bởi, --scriptđược phản đối trong 3.x. Cách tiếp cận này có thể được sử dụng bằng cách áp dụng một hook-save-hook. Cụ thể, thêm các mục sau vào 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

Mã được lấy từ # 8009 .


Cảm ơn đã chứng minh việc sử dụng một cái móc sau lưu. Thật không may, như đã đề cập ở đây, việc lấy lại từ .pytệp vào sổ ghi chép là có vấn đề, vì vậy đây không may là một giải pháp hoàn chỉnh. (Tôi loại mong muốn nó được vì nó là rất tốt đẹp để diff .pyfile thay vì máy tính xách tay Có lẽ mới. Notebook diff Tính năng này sẽ có ích.
mforbes

1
Cảm ơn! Bây giờ tôi đang sử dụng thủ thuật này để tái tạo --scripthành vi, bất kể kiểm soát phiên bản. Tôi đã có một số vấn đề lúc đầu, vì vậy chỉ trong trường hợp tôi có thể tiết kiệm thời gian cho ai đó: 1) Nếu ipython_notebook_config.pythiếu từ thư mục hồ sơ, hãy chạy ipython profile createđể tạo nó. 2) Nếu có vẻ như hook-save-hook bị bỏ qua, hãy chạy ipython --debugđể chẩn đoán sự cố. 3) Nếu lỗi tập lệnh bị lỗi ImportError: No module named mistune- cài đặt đơn giản minstue : pip install mistune.
Joe

7

Thật không may, tôi không biết nhiều về Mercurial, nhưng tôi có thể cung cấp cho bạn một giải pháp khả thi phù hợp với Git, với hy vọng bạn có thể dịch các lệnh Git của tôi thành các tương đương Mercurial của chúng.

Đối với nền, trong Git, addlệnh lưu trữ các thay đổi đã được thực hiện đối với tệp vào khu vực tổ chức. Khi bạn đã thực hiện điều này, mọi thay đổi tiếp theo đối với tệp sẽ bị Git bỏ qua trừ khi bạn bảo nó xử lý chúng. Do đó, tập lệnh sau, đối với mỗi tệp đã cho, loại bỏ tất cả outputsprompt_number sections, giai đoạn tệp bị tước, sau đó khôi phục lại bản gốc:

LƯU Ý: Nếu việc chạy này mang lại cho bạn một thông báo lỗi như thế ImportError: No module named IPython.nbformat, thì hãy sử dụng ipythonđể chạy tập lệnh thay vì 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)

Khi tập lệnh đã được chạy trên các tệp có thay đổi bạn muốn cam kết, chỉ cần chạy git commit.


Cám ơn vì sự gợi ý. Mercurial không thực sự có khu vực tổ chức như git (mặc dù người ta có thể sử dụng hàng đợi đồng bóng cho mục đích này). Trong thời gian chờ đợi, tôi đã thử thêm mã này vào một móc lưu để lưu phiên bản sạch với .cleantiện ích mở rộng. Thật không may, tôi không thể thấy cách thực hiện việc này mà không sửa đổi trực tiếp IPython (mặc dù thay đổi này khá nhỏ). Tôi sẽ chơi với nó một lúc và xem nó có phù hợp với tất cả các nhu cầu của tôi không.
mforbes

6

Tôi sử dụng một cách tiếp cận rất thực dụng; hoạt động tốt cho một số máy tính xách tay, ở một số mặt. Và nó thậm chí còn cho phép tôi 'chuyển' sổ ghi chép xung quanh. Nó hoạt động cả cho Windows dưới dạng Unix / MacOS.
Al nghĩ nó đơn giản, là giải quyết các vấn đề trên ...

Ý tưởng

Về cơ bản, không theo dõi các .ipnyb-files, chỉ các .py-files tương ứng .
Bằng cách khởi động máy chủ sổ ghi chép với --scripttùy chọn, tệp đó sẽ tự động được tạo / lưu khi sổ ghi chép được lưu.

Những .py-files đó chứa tất cả đầu vào; phi mã được lưu vào các bình luận, cũng như các đường viền ô. Những tệp này có thể được đọc / nhập (và kéo) vào máy chủ sổ ghi chép để (tái) tạo sổ ghi chép. Chỉ có đầu ra là biến mất; cho đến khi nó được chạy lại

Cá nhân tôi sử dụng mercurial để theo dõi phiên bản các .pytập tin; và sử dụng các lệnh (dòng lệnh) thông thường để thêm, đăng ký (ect) cho điều đó. Hầu hết các VCS (D) khác sẽ cho phép điều này.

Nó đơn giản để theo dõi lịch sử bây giờ; các .pynhỏ, văn bản và đơn giản để diff. Thỉnh thoảng, chúng tôi cần một bản sao (chỉ là chi nhánh; bắt đầu một máy tính xách tay thứ 2 ở đó) hoặc phiên bản cũ hơn (kiểm tra và nhập vào máy chủ sổ ghi chép), v.v.

Mẹo và thủ thuật

  • Thêm * .ipynb để ' .hgignore ', vì vậy Mercurial biết điều đó có thể bỏ qua các tập tin
  • Tạo một tập lệnh (bash) để khởi động máy chủ (với --scripttùy chọn) và thực hiện theo dõi phiên bản
  • Lưu sổ ghi chép sẽ lưu .pytệp -file, nhưng không kiểm tra.
    • Đây là một nhược điểm : Người ta có thể quên rằng
    • Đây cũng là một tính năng : Có thể lưu sổ ghi chép (và tiếp tục sau) mà không cần phân cụm lịch sử kho lưu trữ.

Mong muốn

  • Sẽ thật tuyệt nếu có một nút để đăng ký / thêm / etc trong Bảng điều khiển của máy tính xách tay
  • Một kiểm tra để (ví dụ) file@date+rev.py) sẽ hữu ích Nó sẽ là nhiều công việc để thêm vào đó; và có lẽ tôi sẽ làm như vậy một lần. Cho đến bây giờ, tôi chỉ làm điều đó bằng tay.

Làm thế nào để bạn đi từ các .pytập tin trở lại một máy tính xách tay? Tôi thích cách tiếp cận này, nhưng vì .ipynb-> .py-> .ipynbcó khả năng bị mất, tôi đã không xem xét điều này một cách nghiêm túc.
mforbes

Điều đó thật dễ dàng: tải nó, ví dụ bằng cách thả nó vào de Notebook-dashboard. Ngoại trừ "dữ liệu đầu ra", không có gì bị mất
Albert

Nếu đó là sự thật, sau đó tôi nghĩ rằng điều này sẽ được gần gũi với ý tưởng, nhưng tôi dường như nhớ lại rằng IPython đã không có cam kết để bảo quản hoàn toàn dữ liệu trong quá trình chuyển đổi từ .pyđể .ipynbđịnh dạng. Có một vấn đề về điều này - vì vậy có lẽ điều này sẽ tạo cơ sở cho một giải pháp hoàn chỉnh.
mforbes

Tôi gặp một số khó khăn khi chuyển đổi từ .pytập tin sang .ipynbtập tin. nbconvertdường như chưa hỗ trợ điều này và tôi không có bảng điều khiển máy tính xách tay kể từ khi tôi chạy ipython notebookthủ công. Bạn có bất kỳ đề xuất chung về cách thực hiện chuyển đổi ngược này không?
mforbes

Chắc chắn việc .pychuyển đổi -to-notebook không nhằm mục đích khứ hồi. Vì vậy, đây thực sự không thể là một giải pháp chung mặc dù nó rất tốt cho bạn.
Holdenweb

3

Để theo dõi kịch bản xuất sắc của Pietro Battiston, nếu bạn gặp lỗi phân tích cú pháp Unicode như thế này:

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)

Bạn có thể thêm vào đầu tập lệnh:

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

3

Tôi đã xây dựng gói python giải quyết vấn đề này

https://github.com/brookisme/gitnb

Nó cung cấp CLI với cú pháp lấy cảm hứng từ git để theo dõi / cập nhật / máy tính xách tay bên trong repo git của bạn.

Đây là một ví dụ

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

Lưu ý rằng bước cuối cùng, nơi tôi đang sử dụng "cam kết gitnb" đang cam kết với repo git của bạn. Nó thực chất là một gói cho

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

Có một số phương thức nữa và có thể được cấu hình để nó yêu cầu đầu vào của người dùng nhiều hơn hoặc ít hơn ở mỗi giai đoạn, nhưng đó là ý tưởng chung.


3

Sau khi đào xung quanh, cuối cùng tôi đã tìm thấy cái móc tiền lưu tương đối đơn giản này trên các tài liệu Jupyter . Nó dải dữ liệu đầu ra tế bào. Bạn phải dán nó vào jupyter_notebook_config.pytập tin (xem bên dưới để được hướng dẫn).

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

Từ câu trả lời của Rich Signell :

Nếu bạn không chắc chắn trong thư mục nào sẽ tìm thấy jupyter_notebook_config.pytệp của mình , bạn có thể nhập jupyter --config-dir[vào dấu nhắc lệnh / thiết bị đầu cuối] và nếu bạn không tìm thấy tệp ở đó, bạn có thể tạo tệp bằng cách nhập jupyter notebook --generate-config.


1
Tôi sẽ lưu ý rằng giải pháp này sẽ không bao giờ lưu bất kỳ đầu ra nào vào đĩa và hơi độc lập với vấn đề kiểm soát phiên bản.
bdforbes

2

Tôi đã làm những gì Albert & Rich đã làm - Đừng tập tin phiên bản .ipynb (vì những tệp này có thể chứa hình ảnh, bị lộn xộn). Thay vào đó, luôn luôn chạy ipython notebook --scripthoặc đặt c.FileNotebookManager.save_script = Truevào tệp cấu hình của bạn để tệp (phiên bản) .pyluôn được tạo khi bạn lưu sổ ghi chép của mình.

Để tạo lại sổ ghi chép (sau khi kiểm tra repo hoặc chuyển nhánh) tôi đặt tập lệnh py_file_to_notebooks.py trong thư mục nơi tôi lưu trữ sổ ghi chép của mình.

Bây giờ, sau khi kiểm tra một repo, chỉ cần chạy python py_file_to_notebooks.pyđể tạo các tập tin ipynb. Sau khi chuyển nhánh, bạn có thể phải chạy python py_file_to_notebooks.py -ovđể ghi đè lên các tệp ipynb hiện có.

Để đảm bảo an toàn, bạn cũng nên thêm *.ipynbvào .gitignoretệp của mình .

Chỉnh sửa: Tôi không còn làm điều này bởi vì (A) bạn phải tạo lại sổ ghi chép của mình từ các tệp py mỗi khi bạn kiểm tra một nhánh và (B) có những thứ khác như đánh dấu trong sổ ghi chép mà bạn bị mất. Tôi thay vì loại bỏ đầu ra từ máy tính xách tay bằng bộ lọc git. Thảo luận về cách làm điều này là ở đây .


Tôi thích ý tưởng này, nhưng sau khi thử nghiệm, thấy rằng việc chuyển đổi từ .pycác tệp trở lại .ipynblà có vấn đề, đặc biệt là với các máy tính xách tay phiên bản 4 chưa có bộ chuyển đổi. Hiện tại người ta sẽ cần sử dụng trình nhập v3 sau đó chuyển đổi sang v4 và tôi hơi lo ngại về chuyến đi phức tạp này. Ngoài ra, một .pytập tin không phải là một lựa chọn tốt nếu máy tính xách tay chủ yếu là mã Julia! Cuối cùng, --scriptkhông được dùng nữa nên tôi nghĩ móc là cách để đi.
mforbes 18/2/2015

Giải pháp bộ lọc git trong liên kết của bạn là tốt, bạn nên sao chép câu trả lời của mình từ đây :-)
mcarans

2

Ok, do đó, có vẻ như giải pháp tốt nhất hiện tại, theo như một cuộc thảo luận ở đây , là tạo một bộ lọc git để tự động loại bỏ đầu ra từ các tệp ipynb trên commit.

Đây là những gì tôi đã làm để làm cho nó hoạt động (được sao chép từ cuộc thảo luận đó):

Tôi sửa đổi tập tin nbstripout cfriedline của hơi để cung cấp cho một lỗi thông tin khi bạn không thể nhập các IPython mới nhất: https://github.com/petered/plato/blob/fb2f4e252f50c79768920d0e47b870a8d799e92b/notebooks/config/strip_notebook_output Và thêm nó vào repo của tôi, cho phép nói trong./relative/path/to/strip_notebook_output

Đồng thời thêm tệp .gitattribut vào thư mục gốc của repo, chứa:

*.ipynb filter=stripoutput

Và tạo ra một setup_git_filters.shchứa

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

Và chạy source setup_git_filters.sh. Điều thú vị $ (git rev-parse ...) là tìm đường dẫn cục bộ của repo của bạn trên bất kỳ máy (Unix) nào.


1

Phần mở rộng jupyter này cho phép người dùng đẩy máy tính xách tay jupyter trực tiếp lên github.

Xin vui lòng nhìn vào đây

https://github.com/sat28/githubcommit


bạn có thể giải thích điều này không? Sự nhân đôi không đặc biệt rõ ràng.
Alex Monras

@AlexMonras Điều này sẽ trực tiếp thêm một nút trong sổ ghi chép jupyter từ đó bạn có thể đẩy sổ ghi chép vào repo GitHub của mình bằng một thông điệp cam kết
ngồi vào

1

Đây là tháng 4 năm 2020 và có rất nhiều chiến lược và công cụ để kiểm soát phiên bản máy tính xách tay Jupyter. Dưới đây là tổng quan nhanh về tất cả các công cụ bạn có thể sử dụng,

  • nbdime - Đẹp cho sự khác biệt và hợp nhất của máy tính xách tay

  • nbstripout - Bộ lọc git để tự động xóa đầu ra của sổ ghi chép trước mỗi lần xác nhận

  • jupytext - Giữ một tệp đồng hành .py được đồng bộ hóa với mỗi sổ ghi chép. Bạn chỉ cam kết tập tin .py

  • nbconvert - Chuyển đổi sổ ghi chép thành tập lệnh python hoặc HTML (hoặc cả hai) và cam kết các loại tệp thay thế này

  • Đánh giáNB - Hiển thị khác máy tính xách tay (cùng với đầu ra) cho bất kỳ yêu cầu cam kết hoặc kéo nào trên GitHub. Người ta cũng có thể viết bình luận trên các ô của máy tính xách tay để thảo luận về các thay đổi (ảnh chụp màn hình bên dưới).

nhập mô tả hình ảnh ở đây

Tuyên bố miễn trừ trách nhiệm: Tôi đã xây dựng Đánh giáNB.


0

Làm thế nào về ý tưởng được thảo luận trong bài viết dưới đây, nơi giữ đầu ra của sổ ghi chép, với lập luận rằng có thể mất nhiều thời gian để tạo ra nó và thật tiện lợi vì giờ đây GitHub có thể kết xuất sổ ghi chép. Có các móc tự động lưu được thêm vào để xuất tệp .py, được sử dụng cho diffs và .html để chia sẻ với các thành viên trong nhóm không sử dụng sổ ghi chép hoặc git.

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.