0,0
рейтинг
27 июня 2015 в 15:15

Разработка → «pip -t» — простая альтернатива virtualenv перевод

TL;DR


Чтобы просто установить и изолировать зависимости проекта, virtualenv часто оказывается слишком тяжелым решением. Предлагаем простую альтернативу:
  1. добавить ./.pip в переменную окружения PYTHONPATH,
  2. установить пакеты локально с помощью pip install -t .pip,
  3. запускать python из папки проекта.


Какую версию желаете сегодня?


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

Обычная практика — включать в проект файл requirements.txt. В этом файле перечислены все библиотеки, от которых зависит проект, с номерами версий. Если файл на месте, установить зависимости просто:
$ pip install -r requirements.txt

Пока все хорошо. Плохо станет, если у вас два и больше проектов с конфликтующими зависимостями. Допустим, проект A работает с библиотекой X только версии 0.1, а проект B — 0.2. По умолчанию pip устанавливает библиотеки глобально в папку интерпретатора Питона. Это означает, что команда $ pip install X==0.2 установит библиотеку X версии 0.2 для всех проектов и перезапишет версию 0.1, если та уже установлена. Переключение между A и B означает глобальную переустановку X каждый раз, что долго и неудобно.

Остров под солнцем


Популярное решение этой частой проблемы — виртуальные окружения. Фреймворк virtualenv создает изолированные Питон-окружения. Зависимости каждого проекта отделяются друг от друга. Так или иначе, некоторым пользователям virtualenv кажется слишком сложным. Поэтому существуют пакеты типа virtualenvwrapper и autoenv, которые расширяют функциональность virtualenv, чтобы им было проще пользоваться. Другие решения: Anaconda environments и pyvenv из стандартной библиотеки Питона (3.3+).

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

В мире Яваскрипта npm и Bower предлагают простое, надежное и мощное управление пакетами, которого как будто не хватает в Питоне. Их ключ к успеху в том, что они скачивают правильную версию правильной библиотеки и кладут ее в специальную папку внутри проекта. Скачанные библиотеки относятся только к конкретному проекту. Это автоматически избавляет от проблем, о которых говорилось выше.

Чистая магия


Оказывается, есть простой способ повторить подход npm и Bower в Питоне:
  • добавить ./.pip в PYTHONPATH,
  • использовать pip с параметром -t .pip для локальной установки пакетов.

Затем просто запускаете код из папки проекта. Забудьте про source env/bin/activate и deactivate!

Фокус работает, потому что ./.pip — относительный путь. В результате, когда запускаете python из ~/dev/project_a, папка ~/dev/project_a/.pip включается в список папок библиотек для этого экземпляра Питона. Запускаете python в ~/dev/project_b — включается ~/dev/project_b/.pip. Прием работает на всех популярных платформах: Линуксе, Маке и Виндоузе.

Название папки .pip, конечно, может быть любым. Кому-то больше понравится pip_components или libs. Тем не менее, .pip быстро печатать, а точка в начале делает папку скрытой в Линуксе и Маке.

Шаг 1: Установить PYTHONPATH


  • MAC/LINUX
    Эта команда установит PYTHONPATH навсегда для стандартных терминальных сессий:
    $ echo 'export PYTHONPATH="./.pip:$PYTHONPATH"' >> ~/.bash_profile
    

    После этого перезапустите терминал или исполните $ source .bash_profile, чтобы PYTHONPATH загрузилась в активной сессии. В зависимости от платформы вам, возможно, надо будет заменить ~/.bash_profile на ~/.bashrc.

  • WINDOWS
    Окройте Панель упраления и перейдите в System and Security → System → Change Settings → Advanced → Environment Variables (у меня английская версия, поэтому не перевожу названия разделов, чтобы случайно не запутать читателей. — прим. пер.). Добавьте или отредактируйте переменную PYTHONPATH, чтобы ее значение стало таким: .\.pip или .\.pip;(...other paths...). Можно установить переменную как для пользователя, так и для всей системы.

  • TEMPORARY PYTHONPATH
    Если предпочитаете устанавливать PYTHONPATH только на время сессии, запустите $ export PYTHONPATH=./.pip в Маке и Линуксе или > set PYTHONPATH=.\.pip в Виндовсе.

    В Маке и Линуксе можно даже установить PYTHONPATH только на время Питон-сессии: $ PYTHONPATH=./.pip python main.py.


Шаг 2: Установить пакеты через pip -t


Теперь, когда PYTHONPATH установлена, осталось только установить пакеты в правильное место с помощью pip. Для этого используем ключ -t или --target:
$ cd project_a
project_a$ pip install requests==2.7.0 -t .pip

project_a$ python
>>> import requests
>>> requests.__version__
'2.7.0'

Теперь то же самое в другом проекте с другой версией:
$ cd project_b
project_b$ pip install requests==2.6.0 -t .pip

project_b$ python
>>> import requests
>>> requests.__version__
'2.6.0'

С файлом requirements.txt все работает так же:
$ pip install -r requirements.txt -t .pip


Потенциальные засады


Разные интерпретаторы Питона


Можно легко запустить программу другим интерпретатором Питона:
$ /path/to/python main.py

Тем не менее, есть проблема с переключением между Питоном 2 и 3, если используются пакеты, которые компилируют исходный код во время установки через 2to3. У таких пакетов нет единой кодовой базы, при установке код генерируется соответственно активной версии Питона.

В этом случае создайте папку типа .pip3 и добавьте ее в начало PYTHONPATH, когда запускаете код Питоном 3.

easy_install


Если у вас есть пакеты, установленные глобально через easy_install, столкнетесь с проблемой: easy_install дописывает путь к таким пакетам в начало sys.path, поэтому у них приоритет над пакетами из .pip.

Решение — избавиться от пакетов, установленных глобально через easy_install.

Чтобы проверить, что ничто не мешает использовать .pip, запустите import sys;sys.path в Питоне. Если перед ./.pip будут другие пути, возможно, придется сначала почистить систему от глобальных easy_install-пакетов.
Перевод: Eric Reynolds and Felix Zumstein
Константин Молчанов @moigagoo
карма
15,2
рейтинг 0,0
Техписатель
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

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

  • 0
    Довольно элегантное решение. В Node.js оно радует. Посмотрим обрадует ли в этом случае)
  • +1
    Вот не нужно так делать:
    export PYTHONPATH="./.pip:$PYTHONPATH"

    . Данное действие, скорее всего, добавит текущий каталог в PYTHONPATH, но, возможно и нет. Зависит от того, пуста ли переменная PYTHONPATH. Если вам нужно добавить что‐то в переменные типа *PATH, то используйте ${VARNAME:+:} вместо двоеточия, чтобы не получить в результате пустой элемент, который часто имеет значение вроде «текущий каталог» или «каталог(и) по‐умолчанию».
  • +1
    Мне хватает pyenv c штатным плагином virtualenv.
    Позволяет хранить на машине сколько угодно версий python, встраивается в командный шелл, автоматически включает окружение и переходе в папку и выключает при выходе из неё.

    С pip -t одна сложность — надо не забывать писать параметр. Лучше сделать алиас уже с параметром.
  • +4
    >> Чтобы просто установить и изолировать зависимости проекта, virtualenv часто оказывается слишком тяжелым решением.
    серьёзно? можно реальный пример?
    • –7
      «Тяжесть» решения — субъективная величина. Мне virtualenv через несколько лет использования действительно стал казаться слишком тяжелым для моих задач. Неохота стало делать activate и deactivate. Virtualenvwrapper мне не нравится, да и в Павершелле не работает, а я сейчас почти всегда в нем. Я перестал им пользоваться этими инструментами и начал ставить пакеты глобально. Да, это плохая практика, но мне не мешало. В моем мире virtualenv — слишком тяжелый инструмент.

      Теперь, когда узнал о таком простом приеме, начал использовать его — и не пожалел.

      Если в вашем мире нет примеров, когда virtualenv — это слишком тяжело, пользуйтесь virtualenv ради бога. Никто ж не запрещает. Значит, в вашем мире это идеальный инструмент.
  • +1
    Еще такую штуку рекомендую: nix
    • +1
      ээ, и оно с питон пакетами как-то дружит?
      • 0
        С чем он только не дружит.
        nix-shell так вообще бомба.
      • 0
        Присоединяюсь к предыдущему комментарию.
        По теме: вот ссылки с первой страницы гугла по запросу «nix packet manager python»:
        Getting started with Nix package manager
        RhodeCode and Nix Package Manager
        Nixos Container Example: Python Web Development
        • 0
          >> The following environment can be used in a nixos-container for using traditional python package managers (pip, buildout etc.) in an impure way within a container

          Т.е. тот же virtual env, те же не атомарные апдейты, только надо еще затратить усилия, чтоб заставить это работать. Но зачем?
          • –1
            Это как минимум не хуже venv, а в преспективе — лучше.
  • +1
    Интересное решение, но насколько я понимаю, в отличие от того же virtualenv, оно будет работать только в корне проекта.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.