Python install egg linux

Python на колёсах

Инфраструктура системы пакетов для 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-окружении.

Что за колесо?

Начнём с простого. Что представляют собой ‘колёса’ и чем они отличаются от ‘яиц’? Оба формата являются zip-файлами. Главная разница в том, что egg можно импортировать без распаковки, wheel же придётся распаковать. Хотя нет никаких технических причин, делающих ‘колёса’ неимпортируемыми, поддержка их прямого импорта никогда даже не планировалась.

Другое различие в том, что ‘яйца’ содержат скомпилированные байткод, а ‘колёса’ – нет. Главное преимущество этого в том, что нет необходимости создавать отдельные wheel’ы для каждой версии Python до тех пор, пока не придётся распространять слинкованные через libpython модули. Хотя в новых версиях Python 3 при использовании стабильного ABI даже это уже можно провернуть.

Однако wheel-формат тоже не лишен проблем, некоторые из которых он наследует от ‘яиц’. Например, бинарные дистрибутивы под Linux до сих пор неприемлемы для большинства из-за двух недостатков: Python сам по себе компилируется под Linux в разных формах, и модули линкуются с разными системными библиотеками. Первая проблема вызвана сосуществованием несовместимых версий Python 2: USC2 и USC4. В зависимости от режима компиляции меняется ABI. В настоящее время wheel (насколько я могу судить) не содержит информации о том, с каким режимом Unicode связана библиотека. Отдельная проблема в том, что дистрибутивы Linux меньше совместимы между собой, чем хотелось бы, и обстоятельства могут сложиться так, что сборка, скомпилированная под один дистрибутив, не будет работать на остальных.

Всё это выливается в то, что, вообще говоря, на данный момент бинарные ‘колёса’ нельзя загружать на PyPI как несовместимые с различными системами.

В дополнение ко всему этому wheel сейчас знает только две крайности: бинарные пакеты и пакеты, содержащие чистый python-код. Бинарные пакеты специфичны для Python ветки 2.x. Сейчас это не кажется большой проблемой, потому что цикл 2.x подходит к концу, и пакетов, собранных только для 2.7, хватит надолго. Но если бы вдруг речь пошла про Python 2.8, была бы интересна возможность заявить, что этот пакет не зависит от версии Python, но он содержит бинарники, поэтому он не может не зависеть от архитектуры.

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

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

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

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

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

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

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

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

Читайте также:  Карты навител с ключом windows ce

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

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

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

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

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

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

Вторая проблема чуть серьёзней: как 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 .

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

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

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

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

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

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

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

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

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

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

В сравнении с ‘яйцами’

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

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

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

Источник

Управление пакетами Python при помощи easy_install

Использование easy_install

Для начала установим пакет setuptools для Python версии 2.7:
$ wget pypi.python.org/packages/2.7/s/setuptools/setuptools-0.6c11-py2.7.egg
$ sudo sh setuptools-0.6c11-py2.7.egg

Теперь можно установить любой пакет, находящийся в центральном репозитарии модулей языка Python, который называется PyPI (Python Package Index): pypi.python.org/pypi. Работа с easy_install напоминает работу с пакетными менеджерами apt-get, rpm, yum и подобными. Для примера установим пакет, содержащий оболочку IPython:
sudo easy_install ipython
В качестве аргумента указывается либо имя пакета, либо путь до пакета .egg, находящегося на диске. Обратите внимание, что для выполнения установки требуются права суперпользователя, так как easy_install установлен и сам устанавливает пакеты в глобальный для Python каталог site-packages. Установка easy_install в домашнюю директорию производится следующим образом: sh setuptools-0.6c11-py2.7.egg —prefix=

Поиск пакета на веб-странице:
easy_install -f code.google.com/p/liten liten
Первый аргумент в данном примере — это на какой странице искать, второй — что искать.
Также предусмотрена возможность HTTP Basic аутентификации на сайтах:
easy_install -f user:password@example.com/path/

Читайте также:  Активация forscan для windows полная версия

Установка архива с исходными кодами по указанному URL:
easy_install liten.googlecode.com/files/liten-0.1.5.tar.gz
В качестве аргумента достаточно передать адрес архива, а easy_install автоматически распознает архив и установит дистрибутив. Чтобы этот способ сработал, в корневом каталоге архива должен находиться файл setup.py.

Для обновления пакета используется ключ —upgrade:
easy_install —upgrade PyProtocols

Также easy_install может немного облегчить установку распакованного дистрибутива c исходными кодами. Вместо последовательности команд python setup.py install достаточно просто ввести easy_install , находясь в каталоге с исходниками.

Изменение активной версии установленного пакета:
easy_install liten=0.1.3
В данном случае производится откат пакета liten до версии 0.1.3.

Источник

Parijat’s Weblog

Python packaging: setuptools and eggs

Developing Packages

This document describes how to create a buildable, distributable package out of
python source code.We’ll look at the popular ‘egg’ distribution format.

Also, highly recommended is: virtualenv

What is an egg?

  • Eggs are basically directories that are added to Python’s path.
  • The directories may be zipped.
  • Eggs have some meta-data
    • Dependencies
    • Entry-points
  • May be distributed as source
  • Can be discovered from PyPI

What is easy_install?

A tool to find, download, compile (if needed), and install python packages. It
can install eggs, or even source tarballs, as long as the tarball uses the
standard python setup.py method of building itself.

Egg Terminology

  • Distribution
    • a term used by Python distutils;
    • anything which can be ‘distributed’, really;
    • most common: tarballs, eggs.
  • Source distribution:
    • A distribution that contains only source files
  • Binary distribution:
    • A distribution that contains compiled ‘.pyc’ files and C extensions
    • E.g., RPMs and eggs
  • Egg:
    • A kind of binary distribution
  • Platform dependent eggs:
    • Eggs which contain built C extension modules and are thus tied to an OS
  • ‘develop eggs’ and ‘develop egg links’:
    • develop egg links are special files that allow a source directory to be
      treated as if it were an installed egg. (That is, an egg that you are
      ‘developing’!)
  • Index server and link servers:
    • easy_install will automatically download distributions from the
      Internet. When looking for distributions, it will look at zero or more
      links servers for links to distributions. They will also look on a single
      index server, typically (always) http://www.python.org/pypi . Index servers
      are required to provide a specific web interface.

Example Project

Our sample project consists of this code:

  • package ‘speaker’
    • module dog:
      • class Dog
      • function DogMain
    • module gendibal
      • class Gendibal
      • function GendibalMain
    • module bjarne
      • class Bjarne
      • function BjarneMain
  • pacakge ‘tests’
    • module dog_test
      • class DogTest
    • module gendibal_test
      • class GendibalTest
    • module bjarne_test
      • class BjarneTest

The classes Dog, Gendibal, and Bjarne are “speakers": they all have the
method greeting() which takes no arguments and returns a string containing
something they said. The Dog speaker will, of course, say “Bow, wow!”.
Gendibal is a mathemetician and therefore uses prime numbers in his
greetings. Bjarne likes to talk about C++.

For every module and class, there is a corresponding test module and class.

We shall also have three scripts (i.e., programs that live in a bin
directory somewhere) that are intended to be launched from the command
line. The programs will be:

  • rundog: runs speaker.dog:Dogmain
  • rungendibal: runs speaker.gendibal:GendibalMain
  • runbjarne: runs speaker.bjarne:BjarneMain

Directory Structure

This is the intended directory structure.

  • Speaker is the name of the project, and it will also be the name of our
    package (Speaker-0.1.tgz, for e.g.);
  • Our project contains a package named speaker, where we will put our
    classes; we can add more packages inside later;
  • setup.py and setup.cfg contain information to build our egg.
  • The tests package will contains test code.

Version 0.0: setting up the package

Let’s create some dirs and files:

The find_packages function automatically will discover your python packages
and modules, and pack them up.

The tag_build option appends a tag of our choice to the generated
filename. We’ll see it in action in a second.

  • speaker/__init__.py and tests/__init__.py are empty files.

Now we can build our package:

We have just created a source distribution and a platform-independent egg, even
though we don’t have a single line of useful code yet.

Note: the ‘dev’ in the filename: we’ve told setuptools that our package
is a in-development package and specified the tag ‘dev’ in setup.cfg. This
actually matters when easy_install is figuring out which out of several
versions of a pacakge it should download and install. More on it later.

Version 0.1: making a releasable package

Let’s update our setup.py:

  • Look at find_packages directive: some packages and modules are not going
    to be part of your distribution, because we want the tests and examples package, and the ez_setup.py module, to be available only to people checking out the code, not when they are downloading a built egg. (We haven’t written any exampels yet, but you were going to do it, right? ;-))
  • zip_safe means that the package won’t be unzipped: stuff will run right
    out of the zipped directory! Normally not useful.
  • We always want to set include_package_data to True.

Our first bit of code

We create our first speaker:

and write a test:

Oops! Python does not know where to find our packages yet. So we ‘install’ our
egg as a ‘develop egg’:

This will create the necessary symbolic links for python to find
our packages. Now our code will behave just as if it was
installed, while letting us keep coding away.

Automatic test discovery and running

We specified a collection of tests above (dog_test.py). But we
will be writing a lot of tests, and we want to be able to run all
of them in one shot. We are going to use the ‘nose’ test
discovery and execution tool to find and run our tests.

Читайте также:  Установить spore windows 10

The tests_require line will make easy_install download and put nose in
the current directory if nose is not already installed.

(If it fails the first time; just run python setup.py test again.)

The main function

We have a speaker library, but we don’t have a “main” script
yet. You often have to create a separate file just for the
“main” script, which is (should be) just a wrapper script that
imports some module and calls a function in it. In fact, for a
large package, we may have many “main” scripts, each doing
nothing more than importing the required packages and modules and
calling some function in there.

We can use the setuptools ‘Entry points’ mechanism for this. An
‘entry point’ is the name of some functionality of the
package/application; entry points come in groups; two groups are
pre-defined: “console_scripts” and “gui_scripts”. Setuptools can
auto-generate wrapper scripts for our entry points.

Here is how we can tell setuptools to generate a console script
that does something useful:

Now, when we do a python setup.py develop, or a user installs
our egg, a script called ‘rundog’ will be generated and
automatically put somewhere in the path. The script will called
the DogMain function in the speaker.dog module with no
arguments, and the return value of the function will be the
exit status of the script.

What would the DogMain function be like?

Now, when we run ‘develop’ again, setuptools will generate the rundog script
for us:

We should keep a minimum amount of code in DogMain and put most
of it in discrete, well tested functions. This helps make code
more robust and re-usable.

About version numbers

Until now, other projects using our Speaker package have been
checking out code from our code repository and using it directly.
Now it is time to make an ‘official’ release. We shall release
v0.1 (the version we have been working on, and the one specified
in setup.py) of our package (and remove ‘dev’ from the release
name). For easy_install:

0.1a Pyrex is “a Language for Writing Python Extension Modules”. The
greatest benefit is that Pyrex makes it easy to convert types
between Python and C.

Writing extensions in Pyrex

We’ll demonstrate this with a new speaker class, and we shall choose Gendibal
for this task. Here is the interface to Gendibal:

Gendibal is a mathematical speaker, and happens to like the 10th
prime number a lot. Now we only have to define the Gendibal class:

and add a new entry point:

Note:

  • the definition of this class is in a file with the .pyxsuffix, indicating that this is a Pyrex, not Python file.
  • the definition is a Python definition. Pyrex code can contain normal Python code.

We have not defined the primes function yet. Here is the definition of the
primes function, in the same .pyx file:

This is Pyrex code. It looks very much like Python, with some type annotations.

Building Pyrex extensions

Setuptools can build Pyrex files “out of the box”, as long as the
Pyrex compiler is somewhere on the path. Let’s get Pyrex:

We need to tell setuptools about our extension, though:

And that’s it! We can build the egg:

Note:

  • The Pyrex code gendibal.pyx was converted to C code gendibal.c by the
    Pyrex compiler;
  • The extension gendibal.so was compiled;
  • A wrapper python script gendibal.py to load the extension was automagically
    created for us.

Now there are two tests:

Wasn’t it handy we are using ‘nose’? Our new test is discovered
and run for us without having to add it anywhere.

We can run our new ‘main’ script:

Pyrex can not only be used to convert Python code to C, but it
can help us interface to existing C code/libraries.

Version 0.3: Boost.Python extensions

What about libraries/code in C++? Pyrex does not help there, and
wrapping around C++ code with Python C API can be tricky.
Boost.Python to the rescue.

Writing extensions in Boost.Python

Let’s say we have the following C++ library:

As can be seen, there is a class named BjarneCPP with an
interface very similar to our speaker interface, except that it
has a greet method, instead of our usual greeting method.
There is also a BjarneCPPMain function, that looks like a good
candidate to be a main function in our application. This looks like a useful
library. How do we access it in Python?

We can wrap it in Python like this:

(For convenience and brevity, we’ve added our code in the same file.
Realistically, the code to be wrapped would be in a library, and
we would link against that library at build time.)

As usual, we do not forget to write our tests:

and define an entry point:

Building Boost.Python extensions

Now we need to tell setuptools about the new extension:

And that’s it. We can create an egg:

Again, setuptools has compiled our extension module, linked it
against the libraries specified (boost_python), and generated a
wrapper (‘bjarne.py’) for us.

We can run our tests, and our new test will appear:

Источник

Оцените статью