# Как генерировать Jupyter Notebooks из Python-скриптов с удобством

Все мы любим Jupyter Notebook. Автоматическое форматирование формул `tex` внутри `markdown`, четко описанная структурированная логика в ячейках, ясный путь аналитической мысли в форме цепочек функций, вычислений этими функциями и выводов из этих вычислений. В конце концов, результаты исполнения в виде графиков и чисел, явно представленные прямо в документе сразу после создавшего их кода. Что может быть лучше?

Однако наличествуют проблемы

## Проблемы

1. Дебажить простые скрипты одновременно просто и сложно. Просто - потому что каждая ячейка выполняется независимо, и можно последовательно выполнить логику. Сложно - потому что debuger-инструменты в таких редакторах, как VSCode не заточены для работы с ipynb и не умеют его дебажить. Так же сложно потому, что скрипты ipynb имеют тенденцию разрастаться в пространстве листинга кода и во времени его исполнения, в при классическом дебагинге вы, обычно, проигрываете весь сценарий выполнения документа от начала и до конца - то есть это долго.

2. А вот недостаток критический: плохая поддержка нейросетями LLM. Да, в 2025 году. Конечно, вы всегда можете открыть свой Cursor или Zed, сгенерировать там ipynb и задать мне вопрос - где же плохая поддержка? А вот что я вам отвечу:

- Из-за сложного дебагинга нейросети имеют склонность создавать тестовые скрипты на py, что бы проверять на них. 
- Нейросети испытывают очевидные трудности в запускании ячеек на исполнение. 
- В ipynb - формате картинки и бинарные данные кодируются как base64. Попав в контекст нейросети, такой ipynb (который она воспринимает в первозданном виде, в форме json-формата) очень сильно просаживают обьем затрачиваемых на обработку запроса токенов, потому что при первичной синтаксической и сематической word2vec обработке base64-код это *бессмысленный текст*. Это значит, что пользователь должен следить, что бы вывод нотебука не попадал в контекст при запросах - очевидно, это сложно.
- А ещё я дважды встерчался с багом, при котором нейросеть видит в своем кэше ячейку, которой на самом деле в документе нет (была стерта) и действуют так, будто бы она там есть. 

Я наблюдал описанные проблемы вместе и по отдельности, на разных задачах, многократно, в своем Сursor, на Claude Sonnet 4, GPT 5 и Grok Code Fast 1.

## Решение проблем

Как поступить, если нам, людям, так нравится работать с ipynb? Решение лежит на поверхности: нужно генерировать python-код в его родном формате python-кода, хорошо задокументированного, с комментариями, которые можно скопировать в ячейку markdown и блоками кода, которые можно скопировать в другую ячейку. С таким кодом ни у дебаггера, ни у mypy, ни у LLM не возникнет ни малейших проблем, а если даже проблемы возникнут, решить их будет в разы проще.

И что же, копировать руками из py в ipynb? Нее. Мои руки созданы для более интересных дел. Поэтому я пошел в интернет искать скрипты авто-генерации ноутбуков.


## Обзор инструментов

### Jupytext

Первым в очереди на тестирование оказался популярный jupytext. Я протестировал его на своих файлах и обнаружил маленький недостаток: он не создает markdown ячеек. Мой python-скрипт оказался нарезан на блоки, и каждый блок был помещен в собственную python-ячейку, в том числе и многострочные комментарии с tex-формулами и описанием механики. 

А как же формулы tex? Зачем мне ipynb без математических формул? 

Ну ладно. Оказалось, что всё же можно получить через jupytext markdown. Для этого надо всего лишь просто написать так:

```python

# + [markdown]
# # Заголовок ноутбука
# 
# Это вводный текст в markdown ячейке. Здесь можно писать с форматированием, списками и т.д.

# +
# Это ячейка с кодом Python
print("Hello, world!")

# + [markdown]
# ## Подзаголовок
# 
# Еще один текстовый блок markdown с **жирным** текстом и списком:
# - пункт 1
# - пункт 2

# +
# Еще одна кодовая ячейка
for i in range(3):
    print(i)

```

Удобно? Ну... so-so, как говорят британцы. Самым большим недостатком в моих глазах здесь является даже не принуждение к явной разметке `+ [markdown]` а отсутствие возможности поместить содержимое markdown-ячейки в многострочный комментарий. Нет ничего сложного в том, что бы сказать LLM оформлять будующие ячейки именно так, но довольно дико копировать это содержимое туда-сюда между файлами свободно, а в python начинать расставлять символы `#` в начале каждой строки. А копировать приходится. У нас тут всё же наука, как-никак!

Ну и, если честно, явная разметка файлов тоже немножко раздражает. Не хочется всё время думать о ней.

### ipynb_generator, p2j, py2nb

Поискав в интернете ещё немного, находим несколько библиотек. 

Ipynb_generator (https://github.com/kaizu/ipynb_generator/) - та, которую порекомендовал мне Perplexity - вообще не то, поскольку генерирует ipynb из markdown а не python файла. 

p2j (https://pypi.org/project/p2j/) - та же проблема с комментариями, что и jupytext.

py2nb (https://pypi.org/project/py2nb/) - выглядел самым перспективным, пока не оказалось, что он точно так же не умеет правильно конвертировать ячейку markdown в python-комментарий.

py2notebook-ai (https://pypi.org/project/py2notebook-ai/) - отличная попытка, но я не хочу вносить дополнительную сложность в свою работу, *интегрируя искуственный интеллект* в простенький инструмент

Как гласит народная мудрость: если хочешь, что бы что-то было сделано хорошо - напиши это сам!

## Встречайте - py2jupyter!

Что бы установить, достаточно простого `pip install py2jupyter`. После этого у вас появится команда запуска скрипта `py2jupyter`.

Пользоваться просто: `py2jupyter <имя скрипта>`. По имени программа сама сообразит 

<!-- описание моей библиотеки -->

