Создать свой 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 с билд-машины.

 

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

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

 

 

 

 

 


Comments are closed