Создать свой PyPI репозиторий для рабочего проекта мне пришлось сразу по нескольким причинам: начиная от архитектурных особенностей, заканчивая простотой удобством такого решения. Началось все с того, что наше приложение состоит из набора независимых между собой частей, packages. Соответственно, каждый такой пакет может зависить от любого числа других - как самописных так и нет. В таком случае создавать для каждого пакета свой файл pip-requirements для разворачивания окружения стало сложно и неудобно. Следующая причина - это сделать возможность установки любого пакета нужной верисии не имея доступа к нашей системе контроля версий (mercurial). Все-таки набрать команду “pip install my-package-name” намного проще и быстрее, чем указывать путь к исходникам или source control. И последняя причина для меня была в том, что необходимо следить за всеми зависимостями к внешним библиотекам: не только использовать нужную версию, устанавливать пропатченную, но и иметь список всего используемого в проекте (с этим пунктом возникло больше всего трудностей).

И так, что же представляет собой любой PyPI репозиторий? В простейшем случае - это папка с пакетами. Но для более легкого использования все же удобнее использовать веб-сервер. Так же можно использовать любой, но есть и специально написанные для этого приложения, которые имеют ряд примуществ. Я для себя пока остановился на pypiserver (http://pypi.python.org/pypi/pypiserver). Он достаточно простой, но при этом может работать как stand alone приложение или wsgi приложение с разными веб-серверами. Из недостатков, которые сразу бросились в глаза - это лишь то, что он не поддерживает upload пактов, т.е. команда “python setup.py upload” с ним работать не будет, но это автор обещает исправить в следующих версиях.

Установка pypiserver, самом простом случае выглядит так:

 

  • $ pip install pypiserver
  • $ mkdir ~/packages
  • копируем нужные пакеты в папку ~/packages и запускаем сервер:
  • $ pypi-server -p 8080 ~/packages

 

После чего репозиторий будет доступен по ссылке http://localhost:8080/simple/.

Теперь собственно про создание своих пакетов. С этим хорошо справляется ditsutils, которые идут вместе с Python (к сожалению, не так хорошо, как это будет в Python 3.3).

Для начала создаем в нашем пакете файл setup.py. В простейшем случае он будет выглядеть примерно так:

setup(name='package-name',
      version='0.2.1',
      description='description',
      author='e0ne',
      author_email='e0ne@e0ne.info,
      url='http://blog.e0ne.info',
      packages=['package_name', ],
     )

 

Далее создаем дистрибутив нашего пакета. В моем случае это только питоновские модули, поэтому меня вполне устроил sources distrib:

$ python setup.py bdist 

Эта команда создаст каталог dist и положит туда архив с дистрибудивом пакета, который, в моем случае, нужно положить в ~/packages. После чего остается лишь выполнить команду для его установки:

$ pip install package-name -i http://localhost:8080/simple

Для более простого использования можно переопределить переменную окружения PIP_INDEX_URL, чтобы еще упростить вызов команды:

$ export PIP_INDEX_URL=http://localhost:8080/simple/
$ pip install package-name

Следующим шагом что нужно сделать - это автоматизировать процесс создангия и выкладывания на свой PyPI-сервер пакетов путем интеграции с continuous integration (CI) сервером. Но так, как это сильно зависит от проекта, выбора CI и структыры исходного кода - приводить пример сдесь не буду. Кому нужно сможет сделать это сам или задать нужные вопросы в комментариях.

И последняя проблема у меня заключалась в том, что нужно полностью отказаться от http://pypi.python.org/pypi по двум причинам: ускорить процесс сборки билда путем удаления необходимости выкачивать нужные зависимости с интернета и иметь полный список всех зависимостей. При этом делать полное зеркало не хотелось. Как оказалось, в Python 2.7 сделать это не так уж и просто (на досуге нужно будет посмотреть как там с этим в Python 3.3). Проблема в том, что pip installer, который у нас используется устанавливает пакеты с помощью стандартных setuptools, что практически аналогично вызову команды “python setup.py install”. И если в setup.py есть строки типа install_requires=’django’, то setuptools не найдет это в локальном репо полезет в интернет. Заставить его работать по-другому без фикса кода можно несколькими способами. Самые простые - это:

 

  • добавить запись в /etc/hosts вида “127.0.0.1    pypi.python.org
  • настроить прокси-сервер для блокирования доступа к pypi.python.org с билд-машины.

 

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

Ссылки по теме:

 

 

 

 

 


 

Мне всегда казалось, что для небольших проектов использование buildout - это как с пушки по воробьям: долго, сложно и неудобно. Хотелось чего-то более простого и понятного. И таким оказалась связка virtualenv + pip.

Про virtualenv я уже писал тут. pip - это замена easy_install, менеджер пакетов для python, который позволяет быстро и удобно устанавливать, обновлять и удалять пакеты. Более подробно можно почитать на официальном сайте. Сейчас же меня интересует возможность быстрого развертывания необходимого окружения для запуска проекта. В двух словах, задача выглядит так:

Нужно запустить проект, который для работы требует следующие пакеты:

 

  • Django;
  • SQL Alchemy;
  • pep8 & pylint для проверки кода.

 

Стандартный алгоритм решения - создать новое окружение с помощью virtualenv и установить нужные пакеты. Но ведь не делать же это каждый раз каждому разработчику руками? А на build-сервере? Пришедшая мне первая мысль (написание нужного bash-скрипта) к счастью, оказалась не совсем правильной. Т.е. для полной автоматизации небольшой bash-скрипт будет не лишним, но вот устанавливать пакеты проще и правильнее через pip. Итак, как же нам установить все необходимые пакеты?

 

Шаг 1. Создаем virtual environment

$ virtualenv ./pip-test/ --no-site-packages

Ключ --no-site-packages указывает на то, что в нашем окружении не будет доступа к пакетам, установленных в операционной системе. Такая себе чистая, ничем не испачканная песочница.

 

Шаг 2. Устанавливаем нужные пакеты

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

$ pip install Django
$ pip install SQLAlchemy
$ pip install pep8
$ pip install pylint

 

Шаг 3. Автоматизируем установку пакетов

После установки нужных пакетов можно выполнить команду pip freeze -l, которая выведет на экран список установленных пакетов с их версиями. В моем случае, это выглядит так:

$ pip freeze -l
Django==1.3.1
SQLAlchemy==0.7.4
logilab-astng==0.23.1
logilab-common==0.57.1
pep8==0.6.1
pylint==0.25.1

 

Ключ -l выводит пакеты установленный только внутри virtualenv, что при создании окружения с ключем --no-site-packages теряет всякий смысл.

Далее этот список нужно сохранить:

$ pip freeze -l > pip-requirements

Тепреь в файле pip-requirements лежит список всех необходимых для запуска пакетов. Этот нужно положить в вашу source control и при необходимости обновлять.

Чтобы установить все необходимые пакеты, необходимо выполнить команду:

$ pip install -r pip-requirements

 

Несколько рускоязычных статей про buildout можно найту тут: http://www.vurt.ru/tag/buildout