Использование ноутбуков IPython под контролем версий


569

Какова хорошая стратегия для хранения ноутбуков IPython под контролем версий?

Формат ноутбука вполне поддается контролю версий: если кто-то хочет управлять версиями ноутбука и выводов, это работает довольно хорошо. Раздражение возникает, когда нужно только контролировать версию входа, исключая выходные данные ячеек (иначе говоря, «продукты сборки»), которые могут быть большими двоичными объектами, особенно для фильмов и сюжетов. В частности, я пытаюсь найти хороший рабочий процесс, который:

  • позволяет мне выбирать между включением или исключением вывода,
  • предотвращает случайное принятие вывода, если я этого не хочу,
  • позволяет мне сохранить вывод в моей локальной версии,
  • позволяет мне видеть, когда у меня есть изменения во входах, используя мою систему контроля версий (то есть, если я только управляю версиями входов, но мой локальный файл имеет выходы, то я хотел бы видеть, изменились ли входы (требующий фиксации Использование команды управления версиями статуса всегда регистрирует разницу, поскольку локальный файл имеет выходные данные.)
  • позволяет мне обновить мою рабочую записную книжку (которая содержит вывод) из обновленной чистой записной книжки. (Обновить)

Как уже упоминалось, если я решил включить выходные данные (что желательно при использовании nbviewer, например), то все в порядке. Проблема в том, что я не хочу, чтобы контроль версий выводился. Существуют некоторые инструменты и сценарии для удаления выходных данных ноутбука, но часто я сталкиваюсь со следующими проблемами:

  1. Я случайно фиксирую версию с выводом, тем самым загрязняя мой репозиторий.
  2. Я очищаю вывод для использования контроля версий, но на самом деле предпочитаю сохранять вывод в моей локальной копии (например, иногда требуется некоторое время для воспроизведения).
  3. Некоторые из сценариев, которые ограничивают вывод, слегка изменяют формат по сравнению с Cell/All Output/Clearопцией меню, создавая тем самым нежелательный шум в diff-файлах. Это решается некоторыми ответами.
  4. При извлечении изменений в чистую версию файла мне нужно найти способ включить эти изменения в мою рабочую тетрадь без необходимости повторного запуска. (Обновить)

Я рассмотрел несколько вариантов, которые буду обсуждать ниже, но пока не нашел хорошего комплексного решения. Полное решение может потребовать некоторых изменений в IPython или может полагаться на некоторые простые внешние сценарии. В настоящее время я использую Mercurial , но хотел бы решение, которое также работает с Git : идеальным решением будет независимость от контроля версий.

Эта проблема обсуждалась много раз, но нет однозначного или четкого решения с точки зрения пользователя. Ответ на этот вопрос должен дать окончательную стратегию. Хорошо, если для этого требуется последняя версия (даже для разработки) IPython или легко устанавливаемое расширение.

Обновление: я играл с моей модифицированной версией ноутбука, которая по желанию сохраняет .cleanверсию при каждом сохранении, используя рекомендации Грегори Кроссвайта . Это удовлетворяет большинству моих ограничений, но оставляет следующее нерешенным:

  1. Это еще не стандартное решение (требуется модификация исходного кода ipython. Есть ли способ добиться такого поведения с помощью простого расширения? Требуется какая-то ловушка при сохранении.
  2. Проблема, с которой я сталкиваюсь в текущем рабочем процессе, заключается в получении изменений. Они войдут в .cleanфайл, а затем должны быть каким-то образом интегрированы в мою рабочую версию. (Конечно, я всегда могу перезапустить ноутбук, но это может быть неприятно, особенно если некоторые результаты зависят от длинных вычислений, параллельных вычислений и т. Д.) Я пока не знаю, как решить эту проблему. , Возможно, рабочий процесс, включающий такое расширение, как ipycache, может сработать, но это кажется слишком сложным.

Ноты

Удаление (удаление) вывода

  • Когда ноутбук работает, можно использовать пункт Cell/All Output/Clearменю для удаления вывода.
  • Есть несколько сценариев для удаления вывода, например, скрипт nbstripout.py, который удаляет вывод, но не выдает тот же вывод, что и при использовании интерфейса ноутбука. В конечном итоге это было включено в репозиторий ipython / nbconvert , но оно было закрыто, заявив, что изменения теперь включены в ipython / ipython , но соответствующая функциональность, похоже, еще не была включена. (обновление) При этом решение Грегори Кроссуайта показывает, что это довольно легко сделать, даже не вызывая ipython / nbconvertТаким образом, этот подход, вероятно, работает, если его можно правильно подключить. (Однако присоединение его к каждой системе контроля версий не является хорошей идеей - это должно каким-то образом подключаться к механизму ноутбука).

Телеконференции

вопросы

Тянуть запросы


Звучит как отличная вещь, которую можно добавить в качестве проблемы на github.com/ipython/ipython или отправить запрос на извлечение, который поможет вам в достижении этой цели.
Кайл Келли

4
Если у вас есть рабочий скрипт для удаления выходных данных, вы можете использовать Git-фильтр «clean», чтобы автоматически применять его перед фиксацией (см. Фильтры clean / smudge).
Матиас

1
@foobarbecue Вопрос содержит неудовлетворительные обходные пути: у каждого есть по крайней мере одно ограничение. Теперь, когда PR 4175 был объединен, возможно, будет сформулировано полное решение, но это еще нужно сделать. Как только у меня будет время, я сделаю это (в качестве ответа), если кто-то другой пока что не предоставит удовлетворительного решения.
mforbes

1
@saroele Я еще не нашел рекомендуемое решение: я собирался пойти с --scriptопцией, но это было удалено. Я жду, пока не будут реализованы хуки после сохранения ( которые запланированы ), и в этот момент, я думаю, я смогу предоставить приемлемое решение, объединяющее несколько методов.
mforbes

1
@mforbes Похоже, этот PR был слит через несколько дней после вашего комментария. Не могли бы вы или кто-то более осведомленный, чем я, опубликовать здесь ответ, показывающий, как использовать новую функцию?
КобеДжон

Ответы:


124

Вот мое решение с git. Это позволяет вам просто добавлять и фиксировать (и изменять) как обычно: эти операции не изменят ваше рабочее дерево, и в то же время (перезапуск) записной книжки не изменит вашу историю мерзавцев.

Хотя это, вероятно, может быть адаптировано к другим VCS, я знаю, что это не удовлетворяет вашим требованиям (по крайней мере, независимость от VSC). Тем не менее, он идеально подходит для меня, и хотя он не является чем-то особенно выдающимся, и многие люди, вероятно, уже используют его, я не нашел четких инструкций о том, как реализовать это путем поиска в Google. Так что это может быть полезно для других людей.

  1. Сохраните файл с этим содержимым где-нибудь (для дальнейшего, давайте предположим ~/bin/ipynb_output_filter.py)
  2. Сделайте его исполняемым ( chmod +x ~/bin/ipynb_output_filter.py)
  3. Создайте файл ~/.gitattributesсо следующим содержимым

    *.ipynb    filter=dropoutput_ipynb
    
  4. Запустите следующие команды:

    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
    

Выполнено!

Ограничения:

  • работает только с git
  • в git, если вы находитесь в ветке somebranchи делаете это git checkout otherbranch; git checkout somebranch, вы обычно ожидаете, что рабочее дерево не изменится. Здесь вместо этого вы потеряете вывод и нумерацию ячеек ноутбуков, источник которых отличается между двумя ветвями.
  • Более того, в общем случае вывод не имеет версии, как в случае с решением Грегори. Чтобы не просто выбрасывать его каждый раз, когда вы делаете что-либо, связанное с извлечением, подход можно изменить, сохранив его в отдельных файлах (но обратите внимание, что во время выполнения вышеуказанного кода идентификатор фиксации неизвестен!), и, возможно, версионирование их (но обратите внимание, что для этого потребуется нечто большее, чем a git commit notebook_file.ipynb, хотя, по крайней мере, это избавит git diff notebook_file.ipynbот мусора base64).
  • при этом, между прочим, если вы извлекаете код (т. е. переданный кем-то другим, не использующим этот подход), который содержит некоторый вывод, вывод проверяется нормально. Только продукция местного производства теряется.

Мое решение отражает тот факт, что мне лично не нравится сохранять версии сгенерированного материала - обратите внимание, что объединение с выводом почти гарантированно сделает недействительным вывод, или вашу производительность, или оба.

РЕДАКТИРОВАТЬ:

  • если вы примете решение, как я предлагал, то есть глобально, у вас будут проблемы в случае, если для какого-то git-репо вы захотите вывести версию. Поэтому, если вы хотите отключить фильтрацию выходных данных для конкретного репозитория git, просто создайте внутри него файл .git / info / attribute с

    **. ipynb filter =

как содержание. Понятно, что таким же образом можно сделать и обратное: включить фильтрацию только для определенного репозитория.

  • код теперь поддерживается в собственном git-репо

  • если приведенные выше инструкции приводят к ImportErrors, попробуйте добавить «ipython» перед путем к сценарию:

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

РЕДАКТИРОВАТЬ : май 2016 г. (обновлено в феврале 2017 г.): у моего сценария есть несколько альтернатив - для полноты, вот список тех, кого я знаю: nbstripout ( другие варианты ), nbstrip , jq .


2
Как вы решаете проблему включения изменений, которые вы тянете? Вы просто живете с необходимостью восстановить все результаты? (Я думаю, что это проявление вашего второго ограничения.)
mforbes

1
@zhermes: эта расширенная версия должна быть в порядке
Пьетро Баттистон

1
Есть ли способ использовать этот метод git filters с внешним инструментом diff? Фильтр применяется, если я использую обычный инструмент командной строки, но не если я использую meld в качестве инструмента сравнения. stackoverflow.com/q/30329615/578770
FA

1
Чтобы избежать получения, ImportErrorя должен был изменить вышеперечисленное для запуска с использованием ipython:git config --global filter.dropoutput_ipynb.clean ipython ~/bin/ipynb_output_filter.py
chris838

1
Потрясающее решение Pietro, спасибо :) Я изменил 2 вещи при использовании вашего сценария в моем случае: 1) Я предпочел объявить фильтр в .gitattributes в корне репозитория, а не у ~/.gitattributesдругих людей те же фильтры, что и у меня 2 ) Я определил регулярное выражение как workdir/**/*.ipynb filter=dropoutput_ipynbи помещаю большинство своих записных книжек в workdir / =>, если я все еще хочу отправить записную книжку с выводом и насладиться закладкой рендеринга в github, я просто помещаю ее вне этой папки.
Свенд

63

У нас есть совместный проект, в котором продуктом является Jupyter Notebooks, и в течение последних шести месяцев мы используем подход, который отлично работает: мы активируем сохранение .pyфайлов автоматически и отслеживаем как .ipynbфайлы, так и .pyфайлы.

Таким образом, если кто-то хочет просмотреть / загрузить последнюю записную книжку, он может сделать это через github или nbviewer, а если кто-то хочет увидеть, как изменился код записной книжки, он может просто посмотреть на изменения в .pyфайлах.

Для Jupyterсерверов ноутбуков это может быть достигнуто путем добавления строк

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

в jupyter_notebook_config.pyфайл и перезапустите сервер ноутбука.

Если вы не уверены, в каком каталоге найти ваш jupyter_notebook_config.pyфайл, вы можете ввести его jupyter --config-dir, а если вы не найдете его там, вы можете создать его, набрав jupyter notebook --generate-config.

Для Ipython 3серверов ноутбуков это может быть достигнуто путем добавления строк

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

в ipython_notebook_config.pyфайл и перезапустите сервер ноутбука. Эти строки взяты из ответа на вопросы github @minrk, и @dror также включает их в свой SO-ответ.

Для Ipython 2серверов ноутбуков это можно сделать, запустив сервер с помощью:

ipython notebook --script

или добавив строку

c.FileNotebookManager.save_script = True

в ipython_notebook_config.pyфайл и перезапустите сервер ноутбука.

Если вы не уверены, в каком каталоге найти ваш ipython_notebook_config.pyфайл, вы можете ввести его ipython locate profile default, а если вы не найдете его там, вы можете создать его, набрав ipython profile create.

Вот наш проект на GitHub, который использует этот подход : и вот пример GitHub для изучения последних изменений в ноутбуке .

Мы были очень счастливы с этим.


1
Спасибо за добавленное доказательство того, что использование --scriptсработало на практике. Проблема с этим в том, что фактические ноутбуки могут быть огромными, если изображения сохраняются. Идеальное решение на этом пути может использовать что-то вроде git-annex, чтобы отслеживать только самый последний полный блокнот.
mforbes,

В Ipython 3.x --scriptэто устарело. ipython.org/ipython-doc/3/whatsnew/version3.html
Дрор

Спасибо @dror, я обновил свой ответ, чтобы предоставить решение minrk ipython 3.x, как вы также предоставили здесь.
Рич Сигнелл

10
Обновление: это решение не работает в iPython версии 4 из-за «Большого раскола» Jupyter от iPython. Чтобы настроить это решение на версию 4, используйте команду jupyter notebook --generate-configдля создания файла конфигурации. Команда jupyter --config-dirвыясняет, в каком каталоге находятся файлы конфигурации. И фрагмент кода, данный @Rich, должен быть добавлен в файл с именем jupyter_notebook_config.py. Остальное работает как раньше.
пельмени мобиус

2
В дополнение к точке по @mobiusdumpling, замените check_call(['ipython'с check_call(['jupyter', в противном случае вы получите предупреждение о том , ipython nbconvertявляется устаревшим , и вы должны использовать jupyter nbconvertвместо этого. (Jupyter v4.1.0, iPython v4.1.2)
cutculus

36

Я создал nbstripoutна основе MinRKs gist , который поддерживает Git и Mercurial (благодаря mforbes). Он предназначен для автономного использования в командной строке или в качестве фильтра, который легко (не) устанавливается в текущий репозиторий через nbstripout install/ nbstripout uninstall.

Получить его из PyPI или просто

pip install nbstripout

Я рассматриваю рабочий процесс, в котором я сохраняю как .ipynb, так и соответствующий .py, автоматически создаваемый с помощью хуков пост-сохранения, описанных выше. Я хотел бы использовать .py для diffs - nbstripout сможет очистить файл .py от счетчиков выполнения ячеек (# In [1] изменено на In [*]), чтобы они не загромождали diff или создать простой сценарий для этого?
Кшиштоф Словиньски

1
@ KrzysztofSłowiński Нет, nbstripoutэтот вариант использования не поддерживается легко, поскольку он основан на формате JSON в блокноте. Скорее всего, вам лучше написать скрипт, специализированный для вашего варианта использования.
Кинан

13

Вот новое решение от Cyrille Rossant для IPython 3.0, которое сохраняется для файлов уценки, а не файлов ipymd на основе json:

https://github.com/rossant/ipymd


Кажется, пока не поддерживаю Jupyter.
К.-Майкл Ай

Я успешно использую ipymd с последней версией Jupyter - вы получаете какую-то конкретную проблему или сообщение об ошибке?
Сирилл Россан

13

После нескольких лет удаления выводов в ноутбуках я попытался найти лучшее решение. Теперь я использую Jupytext , расширение для Jupyter Notebook и Jupyter Lab, которое я разработал.

Jupytext может конвертировать блокноты Jupyter в различные текстовые форматы (Scripts, Markdown и R Markdown). И наоборот. Он также предлагает возможность сопряжения записной книжки с одним из этих форматов и автоматической синхронизации двух представлений записной книжки ( .ipynbи .md/.py/.Rфайла).

Позвольте мне объяснить, как Jupytext отвечает на вышеуказанные вопросы:

позволяет мне выбирать между включением или исключением вывода,

.md/.py/.RФайл содержит только входные ячейки. Вы должны всегда отслеживать этот файл. Версия .ipynbфайла, только если вы хотите отслеживать результаты.

предотвращает случайное принятие вывода, если я этого не хочу,

Добавить *.ipynbв.gitignore

позволяет мне сохранить вывод в моей локальной версии,

Выходы сохраняются в (локальном) .ipynbфайле

позволяет мне видеть, когда у меня есть изменения во входах, используя мою систему контроля версий (то есть, если я только управляю версиями входов, но мой локальный файл имеет выходы, то я хотел бы видеть, изменились ли входы (требующий фиксации Использование команды управления версиями статуса всегда регистрирует разницу, поскольку локальный файл имеет выходные данные.)

Разница в файле .py/.Rили .md- это то, что вы ищете

позволяет мне обновить мою рабочую записную книжку (которая содержит вывод) из обновленной чистой записной книжки. (Обновить)

Вытащите последнюю версию файла .py/.Rили .mdи обновите свой блокнот в Jupyter (Ctrl + R). Вы получите последние входные ячейки из текстового файла с соответствующими выходными данными из .ipynbфайла. На ядро ​​это не влияет, а это значит, что ваши локальные переменные сохраняются - вы можете продолжать работать там, где оставили его.

Что мне нравится в Jupytext, так это то, что блокнот (в виде файла .py/.Rили .mdфайла) можно редактировать в вашей любимой IDE. При таком подходе рефакторинг ноутбука становится легким. Когда вы закончите, вам просто нужно обновить блокнот в Jupyter.

Если вы хотите попробовать это: установите Jupytext с pip install jupytextи перезапустите ваш Jupyter Notebook или Lab editor. Откройте записную книжку, для которой вы хотите управлять версиями, и соедините ее с файлом Markdown (или скриптом ), используя меню Jupytext в записной книжке Jupyter (или команды Jupytext в лаборатории Jupyter). Сохраните свой блокнот, и вы получите два файла: оригинал .ipynbи обещанное текстовое представление блокнота, который идеально подходит для контроля версий!

Для тех, кому это может быть интересно: Jupytext также доступен в командной строке .


13

Обновление : теперь вы можете редактировать файлы Jupyter Notebook непосредственно в коде Visual Studio. Вы можете редактировать записную книжку или преобразованный файл Python.

Наконец-то я нашел продуктивный и простой способ заставить Jupyter и Git хорошо играть вместе. Я все еще на первых шагах, но я уже думаю, что это намного лучше, чем все другие запутанные решения.

Visual Studio Code - это классный и открытый редактор исходного кода от Microsoft. Он имеет отличное расширение Python, которое теперь позволяет импортировать блокнот Jupyter в виде кода Python. Теперь вы также можете напрямую редактировать Jupyter Notebooks .

После того, как вы импортируете свой блокнот в файл Python, весь код и разметка будут вместе в обычном файле Python со специальными маркерами в комментариях. Вы можете увидеть на изображении ниже:

Редактор VSCode с записной книжкой, преобразованной в python

В вашем файле python просто есть содержимое входных ячеек ноутбука. Вывод будет создан в разделенном окне. У вас есть чистый код в блокноте, он не меняется, пока вы просто его исполняете. Нет смешанного вывода с вашим кодом. Нет странного непонятного формата JSON для анализа ваших различий.

Просто чистый код Python, где вы можете легко идентифицировать каждый отдельный diff.

Мне даже не нужно больше версии моих .ipynbфайлов. Я могу поставить *.ipynbстроку .gitignore.

Нужно создать блокнот, чтобы опубликовать или поделиться с кем-то? Нет проблем, просто нажмите кнопку экспорта в интерактивном окне Python

Экспорт файла python в формат Notebook

Если вы редактируете записную книжку напрямую, теперь есть значок Convert and save to a python script. Значки Jupyter в коде Visual Studio

Вот скриншот ноутбука внутри кода Visual Studio:

Редактирование ноутбука внутри VSCode

Я использовал его всего один день, но, наконец, я могу с радостью использовать Jupyter с Git.

PS: завершение кода VSCode намного лучше, чем Jupyter.


12

(2017-02)

стратегии

  • on_commit ():
    • обрезать вывод> name.ipynb ( nbstripout,)
    • обрезать вывод> name.clean.ipynb ( nbstripout,)
    • всегда nbconvertв python: name.ipynb.py ( nbconvert)
    • всегда конвертировать в уценку: name.ipynb.md ( nbconvert, ipymd)
  • vcs.configure ():
    • git difftool, mergetool: nbdiff и nbmerge из nbdime

инструменты

  • nbstripout: убрать выходные данные из записной книжки
  • ipynb_output_filter: убрать выходные данные из записной книжки
  • ipymd: конвертировать между {Jupyter, Markdown, O'Reilly Atlas Markdown, OpenDocument, .py}
  • nbdime: "Инструменты для различий и слияния ноутбуков Jupyter." (2015)
    • источник: https://github.com/jupyter/nbdime
    • документы: http://nbdime.readthedocs.io/
      • nbdiff: сравните ноутбуки в терминале
      • nbmerge: трехстороннее объединение ноутбуков с автоматическим разрешением конфликтов
        • nbdime nbmerge работает как инструмент git merge
      • nbdiff-web: показывает богатый рендеринг различий ноутбуков
      • nbmerge-web: предоставляет веб-инструмент для трехстороннего слияния для ноутбуков
      • nbshow: представьте один ноутбук в удобном для терминала виде

11

Самые популярные ответы 2016 года - это непоследовательные хаки по сравнению с лучшим способом сделать это в 2019 году.

Существует несколько вариантов, лучший из которых ответ на вопрос - Jupytext.

Jupytext

Поймайте статью «Наука о данных» на Jupytext

Как это работает с контролем версий, вы помещаете файлы .py и .ipynb в систему контроля версий. Посмотрите на .py, если вам нужен входной diff, посмотрите на .ipynb, если вы хотите последний обработанный вывод.

Примечательные упоминания: VS studio, nbconvert, nbdime, водород

Я думаю, что немного потрудившись, VS studio и / или водород (или аналогичные) станут доминирующими игроками в решении этого рабочего процесса.


9

Просто попадайтесь на «jupytext», который выглядит как идеальное решение. Он генерирует файл .py из записной книжки, а затем синхронизирует оба файла. Вы можете управлять версиями, различать и объединять входные данные через файл .py без потери выходных данных. Когда вы открываете записную книжку, он использует .py для входных ячеек и .ipynb для вывода. И если вы хотите включить вывод в git, то вы можете просто добавить ipynb.

https://github.com/mwouts/jupytext


9

Поскольку существует очень много стратегий и инструментов для управления версиями для ноутбуков, я попытался создать блок-схему, чтобы выбрать подходящую стратегию (создано в апреле 2019 г.)

Поток решений для выбора стратегии контроля версий


8

Как указывается, --scriptявляется устаревшим в 3.x. Этот подход можно использовать, применив post-save-hook. В частности, добавьте следующее 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

Код взят из # 8009 .


Спасибо за демонстрацию использования крюка после сохранения. К сожалению, как уже упоминалось, возврат из .pyфайла в записную книжку проблематичен, поэтому, к сожалению, это не полное решение. (Я бы хотел, чтобы это было так, как .py
будто

1
Спасибо! Сейчас я использую этот трюк для воспроизведения --scriptповедения независимо от контроля версий. Сначала у меня были некоторые проблемы, так что на всякий случай я могу сэкономить время: 1) Если ipython_notebook_config.pyфайл отсутствует в папке профиля, запустите его ipython profile createдля генерации. 2) Если кажется, что post-save-hook игнорируется, запустите ipython with --debugдля диагностики проблемы. 3) Если сценарий с ошибкой ImportError: No module named mistune- просто установить minstue: pip install mistune.
Джо

7

К сожалению, я мало что знаю о Mercurial, но я могу дать вам возможное решение, которое работает с Git, в надежде, что вы сможете перевести мои команды Git в их эквиваленты Mercurial.

Для фона, в Git add команда сохраняет изменения, внесенные в файл, в промежуточную область. После того, как вы это сделаете, все последующие изменения в файле будут игнорироваться Git, если вы не скажете ему, чтобы они тоже были в стадии разработки. Следовательно, следующий сценарий, который для каждого из заданных файлов удаляет все outputsи prompt_number sections, распаковывает извлеченный файл и восстанавливает исходный:

ПРИМЕЧАНИЕ. Если вы запустили это сообщение об ошибке, например ImportError: No module named IPython.nbformat, используйтеipython вместо запуска используйте сценарий 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)

После запуска сценария для файлов, изменения которых вы хотите зафиксировать, просто запустите git commit.


Спасибо за предложение. У Mercurial на самом деле нет промежуточной области, такой как git (хотя для этой цели можно использовать очереди Mercurial ). Тем временем я попытался добавить этот код в хук сохранения, который сохраняет чистую версию с .cleanрасширением. К сожалению, я не мог понять, как это сделать без непосредственного изменения IPython (хотя это изменение было довольно тривиальным). Я поиграю с этим некоторое время и посмотрю, подходит ли оно всем моим потребностям.
mforbes

6

Я использую очень прагматичный подход; которые хорошо работают для нескольких ноутбуков, с нескольких сторон. И это даже позволяет мне «переносить» ноутбуки вокруг. Он работает как для Windows, так и для Unix / MacOS.
Аль думал, что это просто, это решить проблемы выше ...

концепция

По сути, не отслеживайте .ipnyb-файлы, только соответствующие .py-файлы.
Запуская ноутбук-сервер с --scriptопцией, этот файл автоматически создается / сохраняется при сохранении ноутбука.

Эти .py-файлы содержат все входные данные; не-код сохраняется в комментариях, как и границы ячеек. Эти файлы могут быть прочитаны / импортированы (и перетащены) на ноутбук-сервер для (пере) создания блокнота. Только выход ушел; пока не будет повторного запуска.

Лично я использую Mercurial для отслеживания версий .pyфайлов; и используйте обычные (командная строка) команды для добавления, регистрации (ect) для этого. Большинство других (D) VCS позволит это сделать.

Теперь легко отслеживать историю; .pyмаленькие, текстовые и просто дифф. Время от времени нам нужен клон (просто ветвь; запустите там 2-й блокнот) или более старую версию (извлечение и импорт в ноутбук-сервер) и т. Д.

Советы и хитрости

  • Добавьте * .ipynb в ' .hgignore ', чтобы Mercurial знал, что может игнорировать эти файлы
  • Создайте (bash) скрипт для запуска сервера (с --scriptопцией) и выполните его отслеживание версий
  • Сохранение записной книжки сохраняет .py-файл, но не регистрирует его.
    • Это недостаток : можно забыть, что
    • Это также особенность : можно сохранить записную книжку (и продолжить позже) без кластеризации истории хранилища.

Пожелания

  • Было бы неплохо иметь кнопки для регистрации / добавления / и т.д. в панели инструментов ноутбука.
  • Извлечение (на примере) file@date+rev.py) должно быть полезным. Было бы много работы, чтобы добавить это; и, возможно, я сделаю это один раз. До сих пор я просто делаю это вручную.

Как перейти от .pyфайла обратно в записную книжку? Мне нравится такой подход, но, поскольку .ipynb-> .py-> .ipynbпотенциально с потерями, я не рассматривал это всерьез.
mforbes

Это просто: загрузите его, например, опустив на панель инструментов de Notebook. За исключением «выходных данных» ничего не потеряно
Альберт

Если это правда, то я думаю , что это было бы близко к идее, но я , кажется, напомнит , что IPython не сделали никаких обязательств полностью сохранения данных при переходе от .pyк .ipynbформатам. Есть проблема по этому поводу - так что, возможно, это послужит основой для полного решения.
mforbes

У меня возникли некоторые трудности с преобразованием .pyфайлов в .ipynbфайлы. nbconvertкажется, еще не поддерживает это, и у меня нет приборной панели ноутбука, так как я запускаю ipython notebookвручную. Есть ли у вас какие-либо общие предложения о том, как реализовать это обратное преобразование?
mforbes

Конечно, .pyтрансформация в ноутбук не предназначена для передачи туда и обратно. Так что это не может быть общим решением, хотя приятно, что оно работает для вас.
holdenweb

3

Чтобы продолжить работу над отличным сценарием Пьетро Баттистона, если вы получите ошибку разбора Unicode, подобную этой:

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)

Вы можете добавить в начале сценария:

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

3

Я построил пакет Python, который решает эту проблему

https://github.com/brookisme/gitnb

Он предоставляет интерфейс командной строки с git-вдохновленным синтаксисом для отслеживания / обновления / сравнения записных книжек внутри вашего git-репо.

Вот пример

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

Обратите внимание, что последний шаг, где я использую «gitnb commit» - это фиксация вашего git-репо. По сути, это обертка для

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

Есть еще несколько методов, и их можно настроить так, чтобы на каждом этапе требовалось больше или меньше пользовательского ввода, но это общая идея.


3

Покопавшись, я, наконец, нашел этот относительно простой способ предварительного сохранения документации Jupyter . Он удаляет выходные данные ячейки. Вы должны вставить его в jupyter_notebook_config.pyфайл (см. Инструкции ниже).

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

Из ответа Рича Синьелла :

Если вы не уверены, в каком каталоге найти ваш jupyter_notebook_config.pyфайл, вы можете ввести jupyter --config-dir[в командную строку / терминал], а если вы не найдете файл там, вы можете создать его, набрав jupyter notebook --generate-config.


1
Я хотел бы отметить, что это решение никогда не будет сохранять какие-либо выходные данные на диск, и в некоторой степени не зависит от проблемы управления версиями.
bdforbes

2

Я сделал то, что сделал Альберт и Рич, - не создавал версии файлов .ipynb (так как они могут содержать изображения, которые становятся грязными). Вместо этого всегда запускайте ipython notebook --scriptили c.FileNotebookManager.save_script = Trueсохраняйте .pyфайл конфигурации, чтобы при сохранении записной книжки всегда создавался (изменяемый) файл.

Чтобы восстановить блокноты (после проверки репо или переключения ветки) я поместил скрипт py_file_to_notebooks.py в каталог, где я храню свои блокноты.

Теперь, после проверки репо, просто запустите python py_file_to_notebooks.pyдля генерации файлов ipynb. После переключения ветки может потребоваться запустить python py_file_to_notebooks.py -ovперезаписать существующие файлы ipynb.

Просто чтобы быть в безопасности, это хорошо, чтобы добавить *.ipynbв свой .gitignoreфайл.

Редактировать: я больше не делаю этого, потому что (A) вам приходится восстанавливать свои записные книжки из py-файлов каждый раз, когда вы извлекаете ветку, и (B) есть другие вещи, такие как уценка в записных книжках, которые вы теряете. Я вместо этого удаляю вывод из ноутбуков, используя git-фильтр. Обсуждение того, как это сделать, здесь .


Мне понравилась эта идея, но после тестирования выяснилось, что преобразование .pyфайлов обратно в .ipynbпроблематично, особенно с ноутбуками версии 4, для которых еще нет конвертера. В настоящее время нужно будет использовать импортер v3, а затем конвертировать в v4, и я немного обеспокоен этой сложной поездкой. Кроме того, .pyфайл не очень хороший выбор, если в записной книжке используется в основном код Джулии! Наконец, --scriptустарела, так что я думаю, что крючки - это путь.
mforbes

Решение git filter в вашей ссылке хорошо, вы должны скопировать свой ответ отсюда :-)
mcarans

2

Итак, похоже, что текущее лучшее решение, согласно обсуждению здесь , состоит в том, чтобы сделать git-фильтр для автоматического удаления выходных данных из файлов ipynb при фиксации.

Вот что я сделал, чтобы заставить это работать (скопировано из того обсуждения):

Я слегка измененный файл nbstripout cfriedline, чтобы дать информативное сообщение об ошибке , когда вы не можете импортировать последнюю IPython: https://github.com/petered/plato/blob/fb2f4e252f50c79768920d0e47b870a8d799e92b/notebooks/config/strip_notebook_output И добавил его к моему репо, позволяет скажем в./relative/path/to/strip_notebook_output

Также добавлен файл .gitattributes в корень репо, содержащий:

*.ipynb filter=stripoutput

И создал setup_git_filters.shсодержащий

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

И побежал source setup_git_filters.sh. Причудливая функция $ (git rev-parse ...) - найти локальный путь вашего репо на любом (Unix) компьютере.


1

Это расширение Jupyter позволяет пользователям загружать ноутбуки Jupyter непосредственно на GitHub.

Пожалуйста, посмотрите здесь

https://github.com/sat28/githubcommit


Вы можете объяснить, что это делает? Думенация не особенно понятна.
Алекс Монрас

@AlexMonras Это будет непосредственно добавить кнопку в jupyter ноутбук, где вы можете нажать ноутбуки на ваш GitHub репо с коммита
сидел

1

Это апрель-2020, и есть много стратегий и инструментов для контроля версий ноутбуков Jupyter. Вот краткий обзор всех инструментов, которые вы можете использовать,

  • nbdime - отлично подходит для локального сравнения и объединения ноутбуков

  • nbstripout - фильтр git для автоматического удаления выходных данных ноутбука перед каждым коммитом

  • jupytext - сохраняет сопутствующий файл .py для каждой записной книжки. Вы фиксируете только файлы .py

  • nbconvert - конвертирует записные книжки в скрипт Python или HTML (или оба) и фиксирует эти альтернативные типы файлов

  • ReviewNB - показывает разность записной книжки (вместе с выводом) для любого запроса на фиксацию или извлечение на GitHub. Можно также написать комментарии к ячейкам блокнота, чтобы обсудить изменения (скриншот ниже).

введите описание изображения здесь

Отказ от ответственности: я построил ReviewNB.


0

Как насчет идеи, обсуждаемой в посте ниже, где следует сохранять выходные данные записной книжки с аргументом, что ее генерация может занять много времени, и это удобно, поскольку GitHub теперь может отображать записные книжки. Для экспорта .py-файла добавлены хуки автосохранения, используемые для diff-файлов и .html для обмена с членами команды, которые не используют блокноты или git.

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.