Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Python на колёсах

Anna | 15.06.2014 | нет комментариев
Инфраструктура системы пакетов для Python длинно подвергалась критике как от разработчиков, так и от системных менеджеров. Длинное время даже само комьюнити не могло прийти к соглашению, какие именно инструменты применять в всяком определенном случае. Теснее существуют distutils, setuptools, distribute, distutils2 в качестве базовых механизмов распространения и virtualenv, buildout, easy_install и pip в качестве высокоуровневых инструментов управления каждому этим беспорядком.

До setuptools основным форматом распространения были начальные файлы либо некоторые бинарные MSI-дистрибутивы для Windows. Под Linux были первоначально сломанный bdist_dumb и bdist_rpm, тот, что работал только на системах, основанных на Red Hat. Но даже bdist_rpm работал неудовлетворительно отлично для того, Дабы люди начали его применять.

Несколько лет назад PJE попытался поправить эту задачу, предоставив смесь из setuptools и pkg_resources для совершенствования distutils и добавления метаданных в Python-пакеты. В дополнение к этому он написал утилиту easy_install для их установки. По причине отсутствия формата распространения, поддерживающего метаданные, был предоставлен формат ‘яиц’ [egg].

Python eggs – обыкновенные zip-архивы, содержащие python-пакет и нужные метаданные. Правда многие люди, возможно, никогда специально не собирали egg’и, их формат метаданных до сих пор жив-здоров. И все разворачивают свои планы с применением setuptools.

К сожалению, некоторое время через сообщество разделилось, и часть его провозгласила гибель бинарных форматов и ‘яиц’ в частности. Позже этого pip, замена easy_install, перестал принимать egg-формат.

Потом прошло еще немножко времени, и отказ от бинарных пакетов стал доставлять неудобства. Люди всё огромнее и огромнее стали деплоить на облачные сервера, а надобность перекомпиляции C-шных библиотек на всякой машине не слишком радует. Так как ‘яйца’ на тот момент были малопонятны (я так предполагаю), их переделали в новых PEP-ах, и назвали ‘колёсами‘ [wheels].

В последующем предполагается, что все действия происходят в virtualenv-окружении.
s_rqvmk!
Исключительный случай, оправдывающий существование такого пакета – это когда он содержит распределенные библиотеки, загружаемые с ctypes из CFFI. Такие библиотеки не связаны через libpython и не зависимы от реализации языка (их дозволено применять даже с pypy).

Но есть и ясная сторона: ничто не воспрещает применять бинарные wheel’ы в своих собственных однородных инфраструктурах.

Сборка колеса

Выходит, сейчас мы знаем, что такое wheel. Как сделать своё собственное ‘колесо’? Сборка из собственных библиотек – примитивный процесс. Всё, что необходимо – свежая версия setuptools и библиотека wheel. Как только они оба установлены, ‘колесо’ собирается дальнейшей командой:

$ python setup.py bdist_wheel

Wheel будет сделан в директории пакета. Впрочем есть одна вещь, которой следует бояться: распространение бинарников. По умолчанию собираемое ‘колесо’ (при условии, что в setup.py не применяется никаких бинарных шагов) состоит из pure-python кода. Это значит, что даже если распространять .so.dylib либо.dll как часть своего пакета, полученное ‘колесо’ будет выглядеть платформо-само­стоятельным.

Решение этой задачи – вручную реализовать Distribution из setuptools, скинув флаг чистоты в false:

import os
from setuptools import setup
from setuptools.dist import Distribution

class BinaryDistribution(Distribution):
    def is_pure(self):
        return False

setup(
    ...,
    include_package_data=True,
    distclass=BinaryDistribution,
)

Установка колеса

С применением свежей версии pip ‘колесо’ ставится дальнейшим образом:

$ pip install package-1.0-cp27-none-macosx_10_7_intel.whl

Но что с зависимостями? Здесь возникают некоторые трудности. Традиционно одним из требований к пакету является вероятность его установки даже без подключения к интернету. К счастью, pip разрешает отключать загрузку из индекса и устанавливать директорию, содержащую всё нужное для установки. Если у нас есть wheel’ы для всех зависимостей нужных версий, дозволено сделать следующее:

$ pip install --no-index --find-links=path/to/wheels package==1.0

Таким образом будет установлена версия 1.0 пакета package в наше виртуальное окружение.

Колёса для зависимостей

Окей, но что, если у нас нет .whl для всех наших зависимостей? Pip в теории разрешает решить эту задачу применением команды wheel. Это должно трудиться как-то так:

pip wheel --wheel-dir=path/to/wheels package==1.0

Эта команда выгрузит все пакеты, от которых зависит наш пакет, в указанную папку. Но есть пара задач.
Первая состоит в том, что в команде в подлинный момент есть баг, тот, что не выгружает зависимости, которые теснее являются ‘колёсами’. Так что если связанность теснее доступна на PyPI в wheel-формате, она не будет загружена.

Это временно решается shell-скриптом, тот, что вручную перемещает из кэша скачанные wheel’ы.

#!/bin/sh
WHEEL_DIR=path/to/wheels
DOWNLOAD_CACHE_DIR=path/to/cache
rm -rf $DOWNLOAD_CACHE_DIR
mkdir -p $DOWNLOAD_CACHE_DIR

pip wheel --use-wheel -w "$WHEEL_DIR" -f "$WHEEL_DIR" \
  --download-cache "$DOWNLOAD_CACHE_DIR" package==1.0
for x in "$DOWNLOAD_CACHE_DIR/"*.whl; do
  mv "$x" "$WHEEL_DIR/${x##*%2F}"
done

Вторая задача чуть серьёзней: как pip обнаружит наш личный пакет, если его нет на PyPI? Верно, никак. Документация в таком случае рекомендует применять не pip wheel package, а pip wheel -r requirements.txt, где requirements.txt содержит все нужные зависимости.

Сборка пакетов c применением DevPI

Такое временное решение задачи зависимостей абсолютно применимо в примитивных обстановках, но что делать, если есть уйма внутренних python-пакетов, зависящих друг от друга? Такая конструкция стремительно разваливается.

К счастью, в прошлом году Holker Krekel сотворил решение этой беды под наименованием DevPI, тот, что по существу является хаком, эмулирующим работу pip с PyPI. Позже установки на компьютер DevPI работает как прозрачный прокси перед PyPI и разрешает pip-у устанавливать пакеты из локального репозитория. К тому же все пакеты, скачанные с PyPI, механически кэшируются, так что даже если отключить сеть, эти пакеты будут доступны для установки. И, в конце концов, возникает вероятность загрузки своих собственных пакетов на локальный сервер, Дабы ссылаться на них так же, как и на хранящиеся в публичном индексе.

Я рекомендую установить DevPI в локальный virtualenv, позже чего добавить ссылки на devpi-server и devpiв PATH.

$ virtualenv devpi-venv
$ devpi-venv/bin/pip install --ugprade pip wheel setuptools devpi
$ ln -s `pwd`/devpi-venv/bin/devpi ~/.local/bin
$ ln -s `pwd`/devpi-venv/bin/devpi-server ~/.local/bin

Позже этого остаётся легко запустить devpi-server, и он будет трудиться до ручной остановки.

$ devpi-server --start

Позже запуска его нужно однажды проинициализировать:

$ devpi use http://localhost:3141
$ devpi user -c $USER password=
$ devpi login $USER --password=
$ devpi index -c yourproject

Так как я использую DevPI ‘для себя’, имена пользователя DevPI и системного пользователя совпадают. На последнем шаге создаётся индекс по имени плана (при необходимости дозволено сделать несколько).

Для перенаправления pip на локальный репозиторий дозволено сделать экспорт переменной окружения:

$ export PIP_INDEX_URL=http://localhost:3141/$USER/yourproject/ simple/

Я размешаю эту команду в скрипт postactivate моего virtualenv для предотвращения случайной загрузки из неверного индекса.

Для размещения собственных wheel’ов в локальном DevPI применяется утилита devpi:

$ devpi use yourproject
$ devpi upload --no-vcs --formats=bdist_wheel

Флаг --no-vcs отключает магию, которая пытается определить систему контроля версий и перемещает некоторые файлы в первую очередь. Мне это не необходимо, так как в моих планах распространяются файлы, которые я не включаю в VCS (бинарники, скажем).

Напоследок я настойчиво рекомендую разбить файлы setup.py таким образом, что PyPI их отвергнет, а DevPI примет, Дабы нечаянно не зарелизить свой код с поддержкой setup.py resease. Самый примитивный метод это сделать – добавить неверный классификатор PyPI:

setup(
    ...
    classifier=['Private :: Do Not Upload'],
)

Заворачиваем

Сейчас всё готово для начала применения внутренних зависимостей и сборки собственных ‘колёс’. Как только они появятся, их дозволено заархивировать, загрузить на иной сервер и установить в обособленный virtualenv.
Каждый процесс станет чуть проще, когда pip wheel перестанет игнорировать существующие wheel-пакеты. А пока приведенный выше shell-скрипт – не худшее решение.

В сопоставлении с ‘яйцами’

Теперь wheel-формат больше притягателен, чем egg. Его разработка энергичнее, PyPI начал добавлять его поддержку и, так как с ним начинают трудиться утилиты, он схож на лучшее решение. ‘Яйца’ пока что поддерживаются только easy_install, правда множество давным-давно перешло на pip.

Я считаю, что сообщество Zope до сих пор крупнейшее из основывающихся на egg-формате и buildout. И я считаю, что если решение на основе ‘яиц’ в вашем случае применимо, его и стоит использовать. Я знаю, что многие не применяют eggs совсем, выбирая создавать virtualenv-ы, архивировать их и рассылать по различным серверам. Как раз для такого развёртывания wheels – лучшее решение, так как у различных серверов могут быть различные пути к библиотекам. Встречалась задача, связанная с тем, что .pyc-файлы создавались на билд-сервере для virtualenv, а эти файлы содержат определенные пути к файлам. С применением wheel .pycсоздаются позже установки в виртуальное окружение и механически будут иметь правильные пути.

Выходит, сейчас он у вас есть. Python на колёсах. И это как бы даже работает, и, допустимо, стоит потраченного времени.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB