Перейти к содержимому

Wheel python что это

  • автор:

Tech blog by @dizballanze

Python wheels для быстрой установки зависимостей

Часто все зависимые python пакеты устанавливаются при помощи pip из PyPI и/или VCS. Такой подход имеет ряд недостатков:

  • производительность — каждый раз необходима скачивать и собирать пакеты что занимает большое количество времени
  • работа в оффлайн режиме — без подключения к интернету не получится установить зависимости
  • стабильность — установка зависимостей невозможна в случае:
    • неполадок на стороне PyPI
    • неполадок на стороне VCS (GitHub, Bitbucket, etc)
    • нарушения зависимостей (удаление репозитория с Github, удаление пакета из PyPI и тд)
    • неполадок у хостинг провайдера, которые могут привести к недоступности необходимых сетевых ресурсов (PyPI, VSC, etc)

    Для решения этой проблемы предлагается использование заранее подготовленных пакетов wheel для всех зависимостей и хранение их в репозитории системы.

    Создаем архив wheel пакетов

    Wheel — это современный формат распространения пакетов в Python среде, который пришел на замену eggs. Рассмотрим процесс создания архива wheel для всех зависимостей системы.

    Представим типичный Python проект с файлом requirements.txt содержащим зависимости. Пример файла requirements.txt :

    svgwrite==1.1.6 ipython==2.3.0 flask==0.10.1 flask-mongoengine==0.7.1 flask-uploads==0.1.3 -e git://github.com/Samael500/flask-principal.git@dab7f391f0eeb76a25fa1b3dae7308a0924c8a12#egg=flask-principal -e git://github.com/Samael500/flask-security.git@f1042b5db67147b8ddaa8b767b2dfe063bb56ffa#egg=flask-security Flask-Admin==1.0.8 Flask-Session==0.1.1 Flask-Script==2.0.5 gunicorn==19.1.1 Flask-Testing==0.4.2 tornado==4.0.2 nose==1.3.4 pep8==1.5.7 Pillow==2.6.1 pyflakes==0.8.1 pylama==6.1.1 spec==0.11.1 py-bcrypt==0.4 WTForms==1.0.4 blessings==1.6 beautifulsoup4==4.3.2 lxml==3.4.1 -e git://github.com/Samael500/jinja-assets-compressor.git@8e1639cec6f8b347794fe1334519daacc6b763b0#egg=jac PyYAML==3.10 

    В нашем файле requirements.txt есть зависимости из внешних ресурсов (не PyPI), которые предполагают загрузку пакетов из VCS (в данном случае из git репозиториев на Github). Скопируем старый requirements.txt в requirements-remote.txt , а в requirements.txt заменим внешние ресурсы на обычные пакеты из PyPI и получим:

    svgwrite==1.1.6 ipython==2.3.0 flask==0.10.1 flask-mongoengine==0.7.1 flask-uploads==0.1.3 flask-principal flask-security Flask-Admin==1.0.8 Flask-Session==0.1.1 Flask-Script==2.0.5 gunicorn==19.1.1 Flask-Testing==0.4.2 tornado==4.0.2 nose==1.3.4 pep8==1.5.7 Pillow==2.6.1 pyflakes==0.8.1 pylama==6.1.1 spec==0.11.1 py-bcrypt==0.4 WTForms==1.0.4 blessings==1.6 beautifulsoup4==4.3.2 lxml==3.4.1 jac PyYAML==3.10

    Это делается для того, чтобы при установке из архива wheel пакетов не происходили запросы к внешним VCS, а брались локальные wheel, которые мы сейчас будем генерировать.

    Cоздаем и активируем venv :

    pyvenv venv . venv/bin/activate

    Устанавливаем все пакеты как обычно, но из requirements-remote.txt :

    pip install -r requirements-remote.txt

    Сгенерируем архив всех пакетов PyPI, всех их зависимостей и всех зависимостей внешних пакетов (VCS). Для этого нам потребуется свежая версия pip и пакет wheel :

    pip install -U pip pip install wheel mkdir wheels pip wheel -w wheels/ -r requirements-remote.txt --pre --allow-all-external

    После этого получаем архив wheel пакетов для всех зависимостей кроме внешних (VCS). Для внешних пакетов устанавливаемых из исходников необходимо сгенерировать пакеты вручную при помощи setup.py bdist_wheel :

    cd venv/src/flask-principal python setup.py bdist_wheel --dist-dir ../../../wheels/ cd ../flask-security python setup.py bdist_wheel --dist-dir ../../../wheels/ cd ../jac python setup.py bdist_wheel --dist-dir ../../../wheels/

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

    pip install --no-index -f wheels/ -r requirements.txt

    обратите внимание, что используется файл requirements.txt , а не requirements-remote.txt .

    Тестирование скорости установки

    Обычная установка со скачиванием пакетов из PyPI и VCS:

    time pip install -r requirements-remote.txt real 4m20.655s user 1m31.242s sys 0m55.539s

    Установка из локального архива wheels:

    time pip install --no-index -f wheels/ -r requirements.txt real 1m3.412s user 0m4.808s sys 0m31.210s

    Из результатов можно сделать вывод, что время установки пакетов из локального архива в нашем случае меньше в 4 раза. Что логично, т.к. пакеты заново не скачиваются из интернета и не компилируются.

    Бонус

    Для удобства написал небольшой скрипт, автоматизирующий сборку пакетов установленных из исходников.

    Пример использования скрипта:

    python build_wheels --sources-dir venv/src/ --wheels-dir wheels/

    Скрипт пройдется по всем поддиректориям venv/src/ и в каждой из них попробует собрать пакет в директорию wheels/ .

    К подготовке и публикации первого пакета Python готовы!

    Python стал одним из самых широко используемых языков программирования. Главным образом объясняется это тем, что мы, его обычные пользователи, можем поделиться своим кодом, обеспечивая другим возможность беспрепятственно им пользоваться. А сделать это можно общепринятым способом, упаковав весь код и загрузив его в каталог программного обеспечения Python (Python Package Index или PyPI), с помощью которого пользователи легко и просто установят ваш пакет, используя инструмент pip.

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

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

    Для работы с текущим руководством представим, что директория со всеми файлами Python, включая нужный нам python_file_0.py, называется test_package. Именно этот пакет мы и намерены опубликовать. Следуя принципу простоты, файл python_file_0.py содержит лишь следующий код, который будет использован по мере нашей готовности импортировать пакет после его публикации:

    1. Подготовка файлов

    Перед тем, как углубиться в детали публикации, сначала структурируем директорию с помощью необходимых вспомогательных файлов. Ниже представлена файловая структура пакета:

    the_root_dir/ |— README.md |— setup.py |— test_package | |— __init__.py | |— python_file_0.py | |— python_file_1.py | |— python_file_2.py

    • В корневой директории на одном уровне с test_package создайте файл README.md. Он будет содержать необходимую пользователям информацию о пакете, например сведения об установке и инструкции по применению.
    • На этом же уровне находится файл setup.py. Он будет включать информацию, необходимую для подготовки пакета к публикации. Вскоре мы рассмотрим содержимое этого файла.
    • В директории test_package создайте файл __init__.py именно с таким именем. Он трансформирует обычную директорию в пакет Python. Для этого простого пакета просто поместим код в python_file_0.py и экспортируем from test_package.python_file_0 import hello_world.

    Файл README

    Теоретически для этого файла можно использовать простой текст, но отдав предпочтение файлу Markdown, вы получите разные возможности форматирования и таким образом сделаете его более интересным для чтения. Ниже показан пример простого файла README.md:

    Это тестовый пакет, представляющий собой часть обучающего руководства Meduim.

    **Текст жирным шрифтом**

    *Текст, выделенный курсивом*

    Сборка дистрибутива пакета с помощью Poetry — Python: Настройка окружения

    Когда ваш проект дорастет до того состояния, когда им можно будет с кем-то поделиться, наступит время собрать код. Собранный дистрибутив уже не потребует Poetry — программа запустится и без него.

    На этом этапе нам снова поможет Poetry. В этом уроке мы разберемся, как собрать и установить дистрибутив.

    Сборка и установка дистрибутива

    Обычно poetry-проекты практически сразу пригодны к сборке их дистрибутивов. Есть какие-то особые случаи, требующие дополнительных действий по настройке. Но здесь мы не будем рассматривать их подробно — эти знания пригождаются достаточно редко.

    Простой проект можно собрать командой poetry build :

    (0.1.0) - Building sdist - Built hello-0.1.0.tar.gz - Building wheel - Built hello-0.1.0-py3-none-any.whl 

    Выполним эту команду в корневой директории проекта. После этого там появится директория dist/ с двумя файлами с разными расширениями.

    Сначала рассмотрим файл с расширением .whl — это сокращение от слова wheel («колесо»). Этот файл уже пригоден к установке с помощью pip. Установим его в окружение пользователя:

    -m pip install --user dist/hello-0.1.0-py3-none-any.whl Processing ./dist/hello-0.1.0-py3-none-any.whl Installing collected packages: hello Successfully installed hello-0.1.0 

    Если для проекта описаны какие-то скрипты, то они будут доступны в виде команд. Например, так работает say-hello в нашем случае:

    Часто во время работы над кодом хочется быстро и без лишних усилий попробовать проект в деле.

    Попробуем запустить программу без создания дистрибутива. Чтобы это сделать, укажем путь до директории проекта в качестве имени пакета в команде pip install :

    -m pip install . Processing /. /hello Installing build dependencies . done Getting requirements to build wheel . done Preparing wheel metadata . done Building wheels for collected packages: hello Building wheel for hello (PEP 517) . done Created wheel for hello: filename=hello-0.1.0-py3-none-any.whl size=1671 . Successfully built hello Installing collected packages: hello Successfully installed hello-0.1.0 say-hello Hello! 

    В коде выше мы использовали . — напоминаем, что она означает текущую директорию.

    Установка poetry-проектов из GitHub

    Ранее в этом курсе мы уже говорили, что c помощью pip можно устанавливать пакеты напрямую из GitHub. Так вот, эта возможность доступна и для poetry-проектов. Для установки необходимо выполнить команду pip install git+ с ссылкой на репозиторий:

    install git+https://github.com//

    Открыть доступ

    Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

    • 130 курсов, 2000+ часов теории
    • 1000 практических заданий в браузере
    • 360 000 студентов

    Наши выпускники работают в компаниях:

    Выкладка python-проектов с помощью pip и wheel

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

    image

    Проблема

    Каждый запускает проект по разному; для полноты картины коротко опишу что использую я.

    1. pip и virtualenv для локальной установки пакетов
    2. uwsgi прослойка между nginx и web приложением
    3. supervisor для запуска нужных процессов: uwsgi, celery, tornado и т.д.
    4. nginx запускается под root и смотрит в даль

    В наших проектах мы частенько используем модули, которые в какой то мере написаны на C и требуют компиляции. Тут и начинаются неудобства: на сервере нужно установить компилятор и еще кучу dev пакетов, чтобы скомпилировать зависимости вашего проекта (таких как simplejson или lxml). Первое, что приходит в голову — это взять и скомпилировать локально, а потом просто скопировать на сервер. А что тут такого? И там и там x86_64. Но как оказалось бинарная совместимость это шаткое понятие в Linux системах. Я конечно догадываюсь почему это так, но слабоват чтобы об этом рассуждать. Короче, то что вы скомпилируете у себя на Ubuntu не обязательно будет работать на Debian. Если у вас куча серверов, можно выделить один для сборки пакетов или поднять идентичную виртуальную машину локально и компилировать там.

    При выкладке проекта на боевой сервер есть два варианта: компилировать код на сервере или делать сборку пакетов самому. Лично меня этот скудный выбор расстраивает. Напрашивается вопрос, а почему авторы модулей или PyPi не делает сборку пакетов для разных платформ, есть же бинарные яйца(binary eggs)? Они это делали, и вы даже можете устанавливать их с помощью easy_install, но эта попытка провалилась, так как нет гарантий, то что эти бинарники будут работать у вас на сервере даже с той же версией Python и архитектурой. И наверное на PyPi не у всех пакетов, требующих компиляции, есть бинарные сборки. Кстати, pip не поддерживает бинарные яйца именно по этой причине. А компилировать код на сервере это какой-то больной подход, особенно если серверов для выкладки у вас много, да даже работая за ноутбуком этот процесс просто выбешывает. Все должно быть как то проще: просто скачал и установил.

    Попытка №1

    Когда я занялся этим вопросом в первый раз, я пошел во все тяжкие. Я поднимал свой Debian репозиторий и собирал проект в нативные deb-пакеты. Все было вполне автоматизировано: я написал скрипты для автоматического запуска проекта; на fabric написал скрипт для сборки deb-пакетов и выкладки проекта на сервер. Проект разбивался на три разных deb-пакета: код проекта, virtualenv со всеми модулями, конфигурации (dev, prod). Установка и запуск на сервере заключалась в том, чтобы выполнить одну команду:

    sudo apt-get install my-project-venv my-project-dev-conf my-project 

    Это все конечно здорово, но очень надоедало то, что при обновлении одного модуля в virtualenv приходилось компилировать все модули, чтобы собрать deb-пакет. А еще там было немало танцев с бубном, чтобы сделать непереносимую virtualenv переносимой: переписывать путь в строке !#python во всех файлах в папке bin, удалять все pyc-файлы, удалять все ссылки и устанавливать все пакеты в папке src в папку site-packages. Чтобы проработать эту махину по выкладке, мне пришлось потратить кучу времени и теперь как-то не очевидно, что я сделал свою жизнь проще.

    Попытка №2

    Во второй раз, я решил что лучше собирать все нужные модули в отдельные бинарные пакеты. Наткнулся на относительно новый проект под названием wheel и решил попробовать.

    Wheel — это альтернатива бинарным яйцам; автор старается делать все по последним веяниям, и не так давно его PEP был принят. Из отличий примечательно, что wheel это формат установки, а не импортируемое. Еще wheel хороший помощник при работе на локальной машине: можно скачать и скомпилировать все часто используемые пакеты в одну папку, потом при создании новой виртуальной среды устанавливать пакеты оттуда за O(1).

    1. Поднял свой индекс пакетов: на github есть немало проектов, которые позволяют поднять свой приватный pypi, я использую localshop, потому что в нем есть возможность ограничить доступ на скачивание.
    2. Все зависимости (из requires.txt) собираю в формате wheel и заливаю в свой индекс: для этого мне пришлось немного дописать localshop, так как он не поддерживал этот формат.
    3. Для того чтобы не устанавливать git на сервере, проект так же пакую и кладу в свой индекс пакетов.

    На стороне сервера остается только установить и запустить. Это выглядит примерно так:

    virtualenv myproject . myproject/bin/activate # проект установится и подтянет все зависимости pip install --use-wheel myproject==0.1.1 myproject init myproject runserver 0.0.0.0:8000 

    Запуск под uwsgi:

    pip install --use-wheel uwsgi uwsgi --module=myproject.wsgi --home=myproject . 
    pip install --use-wheel supervisor supervisor -c supervisor.conf -j supervisor.pid 

    Я пишу на Python 2.7.3, который стоит по умолчанию на моей Ubuntu, а на серверах стоит Debian и Python версии 2.6. Конечно же между ними есть разница, например: форматирование строк c помощью format нет на Python 2.6. Пытаться поставить 2.7.3 из дистрибутива не лучшая идея, легче скомпилировать Python и в этом нам хороший помощник — проект pythonbrew.

    Лень — двигатель прогресса! Все мы программисты лентяи(особенно те, кто пишут на Python и Ruby) и, сталкиваясь с неудобствами, мы хотим сделать себе жизнь проще. А как делаете выкладку вы?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *