То, что я пытаюсь сделать и как оно отличается от аналогичных проблем
Я хотел бы управлять версиями Jupyter Notebooks с помощью Git. К сожалению, по умолчанию Git и Jupyter Notebooks не играют хорошо. Файл .ipynb
- это .json
файл, содержащий не только сам код Python, но и множество метаданных (например, счетчик выполнения ячейки) и вывод ячейки.
Большинство существующих решений (например, использование ноутбуков IPython под управлением версий) основаны на удалении вывода и метаданных из ноутбука. Это (i) по-прежнему поддерживает файловую структуру .json
при различении, которая является болью для чтения, и (ii) означает, что такие функции, как отображение вывода в Github, не могут использоваться, поскольку выход удаляется перед фиксацией.
Моя идея такова: всякий раз, когда я запускаю git diff
, Git автоматически использует jupyter nbconvert --to python filename.ipynb
для преобразования из исходных файлов *.ipynb
в *.py
простые файлы python. Затем он должен обнаруживать изменения, которые влияют на сам код (не выполнение отсчетов и вывод, поскольку они удаляются nbconvert
), не удаляя их фактически, и это должно сделать мои отличия более читабельными, чем для неконвертированных файлов .ipynb
. Я не хочу, чтобы .py
версия файла сохранялась навсегда; его следует использовать только для git diff
. Я понимаю, что это должно быть возможно, просто указав nbconvert
качестве nbconvert
[diff] textconv
, но я не смог заставить его работать.
Шаги, которые я выполнил до сих пор
Я создал файл с именем ipynb2py
в /usr/local/bin
содержащий
#!/bin/bash
jupyter nbconvert --to python $1
Я добавил следующее в файл .gitconfig
[diff "ipynb"]
textconv = ipynb2py
и следующее в мой файл .gitattributes
*.ipynb diff=ipynb
назначить драйвер ipynb
textconv всем файлам формата .ipynb
.
Теперь я ожидал бы, что git diff
автоматически выполнит преобразование (я знаю, что это будет существенно замедляться, но стоит иметь жизнеспособный вариант для ноутбуков VCing) каждый раз, когда я его запускаю, а затем показываю хороший читаемый diff, основанный только на различии между состояния ноутбука после преобразования.
Когда я делаю git diff
, он сначала говорит [NbConvertApp] Converting notebook
, который говорит мне, что Git запускает преобразование, как ожидалось. Однако преобразование завершается неудачно после длинной трассировки Python, заканчивающейся fatal: unable to read files to diff
.
Непосредственно перед fatal
сообщением об ошибке я получаю следующее
nbformat.reader.NotJSONError: Notebook does not appear to be JSON: '\n# coding: utf-8\n\n# In[ ]:\n\nimport...
Конечно, я подозревал, что там была проблема с тем, как мой ipynb2py
сценарий ссылающегося nbconvert
, но работает ipynb2py notebook.ipynb
в моем репо работает отлично, так что не может быть причиной.
Что может вызвать эту ошибку? Каковы требования для действительного драйвера textconv
отличного от возврата текстового файла?
Полная трассировка
git diff
[NbConvertApp] Converting notebook /var/folders/9t/p55_4b9971j4wwp14_45wy900000gn/T//lR5q08_notebook.ipynb to python
Traceback (most recent call last):
File "/Users/user/anaconda/lib/python3.6/site-packages/nbformat/reader.py", line 14, in parse_json
nb_dict = json.loads(s, **kwargs)
File "/Users/user/anaconda/lib/python3.6/json/__init__.py", line 354, in loads
return _default_decoder.decode(s)
File "/Users/user/anaconda/lib/python3.6/json/decoder.py", line 339, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/Users/user/anaconda/lib/python3.6/json/decoder.py", line 357, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 2 column 1 (char 1)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/user/anaconda/bin/jupyter-nbconvert", line 11, in <module>
load_entry_point('nbconvert==5.1.1', 'console_scripts', 'jupyter-nbconvert')()
File "/Users/user/anaconda/lib/python3.6/site-packages/jupyter_core/application.py", line 266, in launch_instance
return super(JupyterApp, cls).launch_instance(argv=argv, **kwargs)
File "/Users/user/anaconda/lib/python3.6/site-packages/traitlets/config/application.py", line 658, in launch_instance
app.start()
File "/Users/user/anaconda/lib/python3.6/site-packages/nbconvert/nbconvertapp.py", line 305, in start
self.convert_notebooks()
File "/Users/user/anaconda/lib/python3.6/site-packages/nbconvert/nbconvertapp.py", line 473, in convert_notebooks
self.convert_single_notebook(notebook_filename)
File "/Users/user/anaconda/lib/python3.6/site-packages/nbconvert/nbconvertapp.py", line 444, in convert_single_notebook
output, resources = self.export_single_notebook(notebook_filename, resources, input_buffer=input_buffer)
File "/Users/user/anaconda/lib/python3.6/site-packages/nbconvert/nbconvertapp.py", line 373, in export_single_notebook
output, resources = self.exporter.from_filename(notebook_filename, resources=resources)
File "/Users/user/anaconda/lib/python3.6/site-packages/nbconvert/exporters/exporter.py", line 171, in from_filename
return self.from_file(f, resources=resources, **kw)
File "/Users/user/anaconda/lib/python3.6/site-packages/nbconvert/exporters/exporter.py", line 189, in from_file
return self.from_notebook_node(nbformat.read(file_stream, as_version=4), resources=resources, **kw)
File "/Users/user/anaconda/lib/python3.6/site-packages/nbformat/__init__.py", line 141, in read
return reads(fp.read(), as_version, **kwargs)
File "/Users/user/anaconda/lib/python3.6/site-packages/nbformat/__init__.py", line 74, in reads
nb = reader.reads(s, **kwargs)
File "/Users/user/anaconda/lib/python3.6/site-packages/nbformat/reader.py", line 58, in reads
nb_dict = parse_json(s, **kwargs)
File "/Users/user/anaconda/lib/python3.6/site-packages/nbformat/reader.py", line 17, in parse_json
raise NotJSONError(("Notebook does not appear to be JSON: %r" % s)[:77] + "...")
nbformat.reader.NotJSONError: Notebook does not appear to be JSON: '\n# coding: utf-8\n\n# In[ ]:\n\nimport...
fatal: unable to read files to diff