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

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

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

## Проблемы

1. **Отладка**: по сравнению с обычными python-скрипатами, одновременно и проще и сложнее. Но в основном - сложнее. С одной стороны, можно пошагово выполнять ячейки, что удобно. С другой - debugger-инструменты в редакторах вроде VSCode плохо работают с .ipynb файлами. Сами ноутбуки имеют тенденцию разрастаться, и при классической отладке приходится прогонять весь сценарий от начала до конца, что занимает время.

2. **Проблема с LLM**: да, в 2025 году это всё еще актуально. Современные AI-ассистенты испытывают сложности с ноутбуками по нескольким причинам:

- ИИ предпочитают создавать тестовые .py скрипты для отладки вместо работы с ячейками
- Выводы ячеек (особенно картинки) кодируются в base64, что создает огромное количество "мусорных" токенов в контексте
- JSON-структура .ipynb файлов менее читаема для AI, чем обычный Python код
- Периодически возникают странные баги, когда AI "видят" ячейки, которых уже нет в документе 

Эти проблемы проявляются стабильно на разных платформах - я тестировал на Cursor с Claude Sonnet 4, Grok Code Fast 1 и даже ChatGPT5.

## Решение

А решение, на самом деле, очевидно. Если нам нравятся ноутбуки, но неудобно с ними работать напрямую - давайте писать обычный Python код и автоматически превращать его в красивые ноутбуки.

Хорошо задокументированный .py файл содержит всё необходимое: комментарии можно превратить в markdown ячейки, блоки кода - в code ячейки. С таким подходом и отладчик работает нормально, и LLM не испытывают проблем, и структура кода остается читаемой.

Осталось найти инструмент, который бы это делал элегантно. Ну или написать свой, если готовых решений не найдется.


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

### Jupytext

Первым в очереди на тестирование оказался популярный [jupytext](https://pypi.org/project/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, только хуже. Определил как ячейку markdown все комментарии в файле вообще, и поломал tex-верстку формул.

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

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

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

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


Пользоваться просто: `py2jupyter input.py` создаст `input.ipynb`, а `py2jupyter notebook.ipynb` создаст `notebook.py`. Программа сама определяет направление конвертации по расширению файла.

## Что умеет py2jupyter?

**py2jupyter** решает все перечисленные проблемы и делает это элегантно. Главная фишка - инструмент работает по принципу "умных умолчаний": даже если вы возьмете любой существующий Python файл и скормите его конвертеру, вы получите вполне разумный ноутбук. А если потратите 10 минут на то, чтобы оформить файл согласно простым соглашениям - результат будет ещё лучше.

### Основные возможности

**Двунаправленная конвертация**: py ↔ ipynb с сохранением структуры кода. Можете спокойно работать в любом направлении - от Python к ноутбуку для презентации результатов, от ноутбука к Python для отладки.

**Автоматическое распознавание markdown**: многострочные комментарии `"""..."""` становятся markdown ячейками. Можете писать LaTeX формулы, списки, заголовки - всё будет корректно отображаться в ноутбуке.

**Структурирование кода**: каждая функция и класс попадают в отдельную ячейку. Никаких гигантских ячеек с кодом на пять экранов.

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

**Взаимообратимость**: цикл py → ipynb → py не ломает код. Я использую этот инструмент ежедневно в работе, и он проходит стресс-тест реальными задачами (см [пример](https://github.com/artmihant/py2jupyter/blob/main/example/oscillator_methods.ipynb)).

## Идеология работы с комментариями

Здесь кроется главная изюминка инструмента. Вместо того чтобы заставлять вас изучать специальный синтаксис разметки (как в jupytext), py2jupyter использует естественные конструкции Python.

**Многострочные комментарии** - это ваши будущие markdown ячейки:

```python
"""
Это описание алгоритма станет красивой markdown ячейкой.
Можно использовать **жирный текст**, списки и LaTeX формулы: $E = mc^2$
"""

r"""
А этот блок содержит символы обратного слеша: \alpha, \beta
При обратной конвертации автоматически получит префикс r
"""
```

**Заголовочные комментарии** для структурирования больших скриптов:

```python
""" # Численные методы решения ОДУ # """
```

Становится заголовком первого уровня в ноутбуке.

**Обычные комментарии** `# текст` остаются комментариями - никаких сюрпризов.

**Docstring'и внутри функций** остаются частью кода - это важно для сохранения документации API.

Красота в том, что всё это выглядит естественно в Python коде. Не нужно изучать новый синтаксис или ставить странные маркеры. Просто пишите хороший, документированный код, а py2jupyter превратит его в красивый ноутбук.

## Практические примеры

Допустим, у вас есть такой Python файл:

```python
""" # Анализ данных о продажах # """

"""
В этом скрипте мы проанализируем данные о продажах за последний квартал.
Используем библиотеки pandas и matplotlib для визуализации.
"""

import pandas as pd
import matplotlib.pyplot as plt

def load_sales_data(filename):
    """Загружает данные о продажах из CSV файла"""
    return pd.read_csv(filename)

def analyze_monthly_trends(df):
    """Анализирует месячные тренды продаж"""
    monthly_sales = df.groupby('month')['amount'].sum()
    return monthly_sales

"""
Теперь загрузим данные и построим график тренда:
"""

# Загружаем данные
sales_df = load_sales_data('sales.csv')

# Анализируем тренды  
trends = analyze_monthly_trends(sales_df)

# Строим график
plt.figure(figsize=(10, 6))
trends.plot(kind='bar')
plt.title('Продажи по месяцам')
plt.show()
```

После конвертации получается ноутбук с:
- Заголовком первого уровня
- Markdown ячейкой с описанием
- Ячейкой с импортами  
- Отдельными ячейками для каждой функции
- Markdown ячейкой с пояснением к коду
- Ячейкой с исполняемым кодом

## Magic и shell команды

Отдельно стоит упомянуть поддержку Jupyter magic команд. В Python файле пишете:

```python
#> %matplotlib inline
#> !pip install seaborn
```

В ноутбуке это становится полноценными magic и shell ячейками. При обратной конвертации всё возвращается на свои места.

## Установка и первые шаги

Установка тривиальна:

```bash
pip install py2jupyter
```

Сразу после установки у вас появляется команда `py2jupyter`. Попробуйте её на любом существующем Python файле:

```bash
py2jupyter my_script.py
```

Получите `my_script.ipynb` который можно сразу открыть в Jupyter Lab или Google Colab.

Хотите лучший результат? Потратьте 5 минут на то, чтобы обернуть описательные комментарии в тройные кавычки:

```python
# Вместо такого комментария
# который займет несколько строк
# и будет выглядеть не очень

# Напишите так:
"""
Комментарий который станет красивой markdown ячейкой
с поддержкой LaTeX формул: $\sum_{i=1}^n x_i$
"""
```

Полная документация доступна через `py2jupyter --help`.

## Заключение

py2jupyter - это попытка решить надоевшую проблему простым и понятным способом. Инструмент не претендует на революционность, а просто берет естественные конструкции Python и интерпретирует их здравым смыслом.

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

Исходный код лежит на [GitHub](https://github.com/artmihant/py2jupyter/). Если найдете баги или у вас есть идеи по улучшению — добро пожаловать в issues. Пул-реквесты тоже принимаются. Если понравится — поставьте звездочку, это мотивирует дальше развивать проект.
