Так сложилось, что программный пакет Jupyter как бы не в курсе о существовании виртуальных окружений Python, ключевого инструмента изоляции среды в Python. Информация по этой теме в Сети крайне разрознена. В этой статье собраны все известные автору способы обхода / смягчения этой проблемы; надеюсь, кому-то она поможет не тратить столько дней на задачу, которая должна была быть простой.

Архитектура системы Jupyter сложна. Подробнее можно почитать в документации Jupyter, в документации jupyter_server, в документации jupyter_client, а здесь справка тезисно:

  • Ядро (kernel) — независимый процесс, непосредственно исполняющий код на конкретном языке программирования (используя конкретный экземпляр интерпретатора). Предоставляет сетевой интерфейс с использованием протокола ZeroMQ для передачи исполняемого кода и получения результатов.

    • Ядро ipykernel использует IPython, программный пакет, реализующий Python с расширенными возможностями интерактивной работы.

    • Спецификация ядра (kernel spec) — лёгкие метаданные о ядре со ссылкой на нужный интерпретатор. Установка ядра (install kernel) означает установку спецификации ядра; "установленное ядро" не тратит значительные ресурсы хранилища.

  • Сервер (server) и приложения (web applications) — компоненты, обеспечивающие выполнение пользовательских задач в среде Jupyter.

    • Сервер — процесс, управляющий пользовательскими сессиями, запущенными ядрами, доступом к файловой системе, предоставляющий REST API к своим функциям.

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

      • Jupyter Notebook, JupyterLab относятся именно к таким приложениям — они дают доступ к редактированию блокнотов и выполнению кода (через ядра).

    • Могут существовать также приложения, использующие только REST API сервера, но примеры не известны автору.

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

  • "Ядра устанавливается" либо глобально в систему, либо глобально для отдельного пользователя, либо локально в виртуальное окружение. При этом они делят общее пространство имён. Ядра у пользователя имеют приоритет над ядрами глобально в системе, но приоритет ядер в виртуальных окружениях не определён.

  • Jupyter Core реализует довольно примитивный механизм поиска спецификаций ядер (документация 1, 2). По умолчанию ищутся только глобально установленные ядра (если само приложение Jupyter исполняется в виртуальном окружении, оно видит локально установленные ядра вместо глобально установленных в системе). Можно через переменную окружения JUPYTER_PATH указать места для поиска локально установленных ядер.

  • Расширение Jupyter для Visual Studio Code самостоятельно реализует функции приложения. Однако оно имеет более продвинутый механизм поиска спецификаций ядер. Спецификации ядер, размещённые в виртуальном окружении (в директории данных Jupyter share/jupyter), также подбираются и могут быть использованы пользователем. Они должны иметь локально (в отношении виртуального окружения) уникальные имена, однако они делят пространство имён с глобально установленными ядрами, просто с более высоким приоритетом.

  • Блокнот Jupyter сохраняет ID (name) нужного для его исполнения ядра в своих метаданных (kernelspec.name).

Таким образом, отдельный блокнот требует ядро с определённым именем, это имя ищется в системе глобально. Это мешает переносимости и контролю версий.

Jupyter

В этом разделе описаны варианты использования оригинальной системы Jupyter.

Использование локальных ядер (предпочтительный способ)

Ядро устанавливается локально в виртуальное окружение. Установленные в системе приложения Jupyter настраиваются так, чтобы находить это ядро.

Особенности:

+ Простой порядок работы в случае с единственным виртуальным окружением для каждого блокнота.

Инструкция по настройке проекта (однократной):

  1. Добавьте пакет ipykernel в зависимости Python (requirements.txt / pyproject.toml ...).

  2. Выберите локальный ID для ядра (например, python3_venv).

  3. Не забывайте записывать ID ядра в каждый блокнот в метаданные (kernelspec.name).

Инструкция по установке проекта (в виртуальное окружение, после установки зависимостей Python):

  1. Установите ядро, связанное с виртуальным окружением, в директорию этого виртуального окружения. Укажите ID ядра, используемый блокнотами (см. инструкцию по настройке проекта), вместо NAME. Опционально укажите отображаемое имя ядра вместо DISPLAY_NAME (если не укажете, будет использовано ID ядра). ID/имя ядра нужно, чтобы позже найти его через интерфейс установленного в системе приложения Jupyter.

    python -m ipykernel --sys-prefix --name NAME [--display-name DISPLAY_NAME]
    

    Примечание: Какое-то ядро python3 устанавливается в виртуальное окружение уже при установке ipykernel. Оно ссылается на интерпретатор Python как python; видимо, из-за этого код Jupyter, работающий вне виртуального окружения, запускает установленный в системе интерпретатор Python вместо соответствующего виртуальному окружению. Поэтому это ядро, по-видимому, бесполезно. См. также примечание в инструкции по использованию в разделе Расширение Jupyter для Visual Studio Code.

  2. Опционально, заранее сохраните в переменную окружения JUPYTER_PATH путь к данным Jupyter в виртуальном окружении <path> — см. п. 1 в инструкции по использованию.

    • Windows (PowerShell):

      [System.Environment]::SetEnvironmentVariable('JUPYTER_PATH', "<path>;$env:JUPYTER_PATH", 'User')
      
    • UNIX (sh):

      echo 'export JUPYTER_PATH="<path>:$JUPYTER_PATH"' >> ~/.profile
      

Инструкция по использованию:

  1. Если при выполнении инструкции по установке Вы не сохранили в переменную окружения JUPYTER_PATH путь к данным Jupyter в виртуальном окружении, этот путь нужно добавить в переменную окружения сейчас. Добавьте в переменную окружения JUPYTER_PATH абсолютный путь (далее обозначаемый <path>) $VIRTUAL_ENV/share/jupyter, где следует заменить $VIRTUAL_ENV на путь к директории, где развёрнуто виртуальное окружение. Для инструментов venv, virtualenv можно просто в активном виртуальном окружении использовать подстановку переменной окружения VIRTUAL_ENV (активное виртуальное окружение не повлияет на дальнейшие шаги).

    • Windows (PowerShell):

      $env:JUPYTER_PATH = "<path>;$env:JUPYTER_PATH"
      
    • UNIX (sh):

      export JUPYTER_PATH="<path>:$JUPYTER_PATH"
      
  2. Запустите установленное в системе приложение Jupyter, например, Jupyter Notebook. (Если Вы всё ещё в виртуальном окружении, всё равно запустится именно приложение, установленное в систему, т.к. Вы не устанавливали приложения Jupyter в виртуальное окружение).

    jupyter notebook
    
  3. Используйте приложение Jupyter. Не забывайте выбирать нужное ядро (которое Вы установили локально) при работе с кодом Python.

Веб-приложение/сервер Jupyter внутри виртуального окружения

Нужные приложения Jupyter (или только сервер, если используется приложение, подключаемое по REST API) устанавливаются в виртуальное окружение.

Особенности:

+ Простой порядок работы в случае с единственным виртуальным окружением для проекта.

Высокий расход ресурсов хранилища; пакет notebook версии 7.4 со всеми зависимостями занимает порядка 264 МБ 12 тысячами файлов.

Потенциальные проблемы с более сложными рабочими процессами из-за изоляции среды Jupyter от других проектов.

Инструкция по настройке проекта (однократной):

  1. Опционально, добавьте нужные приложения Jupyter (например, пакет notebook) в список зависимостей Python (requirements.txt / pyproject.toml ...).

Инструкция по установке проекта (в виртуальное окружение, после установки зависимостей Python):

  1. Если Вы не добавили приложения Jupyter в зависимости Python.

    Установите нужные приложения Jupyter (или только сервер Jupyter, если используется приложение, подключаемое по REST API) в виртуальное окружение.

    Например, для веб-приложения Jupyter Notebook (пакет notebook):

    pip install -U notebook
    

Инструкция по использованию:

  1. В виртуальном окружении запустить нужное приложение Jupyter:

    Например, для веб-приложения Jupyter Notebook (пакет notebook):

    jupyter notebook
    
  2. Использовать приложение Jupyter — ядро, выбранное по умолчанию, и будет актуально в виртуальном окружении.

Установка в систему ядер с определёнными именами (не рекомендуется)

См. другой способ в подразделе Использование локальных ядер.

Ядро устанавливается в систему (для пользователя или глобально). Установленные в системе приложения Jupyter видят это ядро без дополнительной настройки.

Особенности:

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

Необходимо обеспечить уникальность ID ядра для проекта. При добавлении условно уникальной строки в ID оно может стать нечитаемым.

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

Установленные спецификации ядер остаются в системе глобально и захламляют систему.

Инструкция по настройке проекта (однократной):

  1. Добавьте пакет ipykernel в зависимости Python (requirements.txt / pyproject.toml ...).

  2. Выберите ID для ядра, глобально уникальный в возможных условиях развёртывания (например, <project-name>-<unique-id>, где <unique-id> — достаточно длинная уникальная строка).

  3. Не забывайте записывать ID ядра в каждый блокнот в метаданные (kernelspec.name).

Инструкция по установке проекта (в виртуальное окружение, после установки зависимостей Python):

  1. Установите ядро, связанное с виртуальным окружением, в систему. Укажите ID ядра, используемый блокнотами (см. инструкцию по настройке проекта), вместо NAME. Опционально укажите отображаемое имя ядра вместо DISPLAY_NAME (если не укажете, будет использовано ID ядра). ID/имя ядра нужно, чтобы позже найти его через интерфейс установленного в системе приложения Jupyter.

    python -m ipykernel --user --name NAME [--display-name DISPLAY_NAME]
    

    Эта команда устанавливает ядро для текущего пользователя. Опционально Вы можете установить ядро глобально, убрав опцию --user.

Инструкция по удалению проекта (помимо других действий):

  1. Удалите ядро, связанное с виртуальным окружением, из системы. Укажите ID ядра, используемый блокнотами (см. инструкцию по настройке проекта), вместо NAME.

    jupyter kernelspec uninstall NAME
    

Инструкция по использованию:

  1. Запустите установленное в системе приложение Jupyter, например, Jupyter Notebook. (Если Вы всё ещё в виртуальном окружении, всё равно запустится именно приложение, установленное в систему, т.к. Вы не устанавливали приложения Jupyter в виртуальное окружение).

    jupyter notebook
    
  2. Используйте приложение Jupyter. Не забывайте выбирать нужное ядро (которое Вы установили в систему, по его уникальному ID/имени) при работе с кодом Python.

Расширение Jupyter для Visual Studio Code

В этом разделе описано использование расширения Jupyter для Visual Studio Code.

Ядро устанавливается локально в виртуальное окружение. Установленные в системе приложения Jupyter настраиваются так, чтобы находить это ядро.

Особенности:

+ Простой порядок работы в случае с единственным ядром для каждого блокнота.

Несовместимость блокнотов, созданных в расчёте на использование этого подхода, со многими другими способами изоляции в Jupyter (кроме установки приложений Jupyter в локальные окружения).

Ограниченный функционал и нестабильность расширения Jupyter для Visual Studio Code.

Инструкция по настройке проекта (однократной):

  1. Добавьте пакет ipykernel в зависимости Python (requirements.txt / pyproject.toml ...).

Инструкция по использованию:

  1. Запустите Visual Studio Code.

  2. Откройте директорию проекта в VS Code.

  3. Если VS Code запрашивает выбор автоматически обнаруженного виртуального окружения, согласитесь.

    Иначе укажите своё виртуальное окружение самостоятельно.

  4. Используйте VS Code с расширением Jupyter. Не забывайте при открытии любого блокнота проверять, что выбрано корректное ядро Jupyter (принадлежащее корректному виртуальному окружению). (Кнопка для выбора ядра для открытого блокнота находится в верхнем правом углу области содержимого вкладки; по умолчанию Вы увидите название выбранного виртуального окружения; если ядро не выбрано, на кнопке написано Select Kernel.)

Примечание: Каким-то неизвестным автору образом расширение Jupyter для Visual Studio Code обходит проблему, описанную в примечании к инструкции по установке в подразделе Использование локальных ядер, не изменяя спецификацию ядра.

Комментарии (0)