Распространяем python-приложения на Windows (и разбираемся с проблемами)

Хотя я предпочитаю linux, как свою основную операционную систему, где мне наиболее комфортно работать, частенько приходится загружаться и в Windows (а, еще, чем черт не шутит, и в мак). И (к сожалению) не только чтобы запустить steam, пристрелить пару гоблинов или побротить по VR мирам.

Недавно надо было отгрузить питоновское приложение для пользователей windows. А на windows, как водится, без проблем ничего не обходится. И в тот момент закономерный вопрос — почему просто не через pip? А вот уже пошли дьявольские подробности, которые я описал у себя в бложике.

Потому что какую-то картинку воткнуть надо было…

Почему не pip? (Придется качать. И качать много!)

Приложение у меня вообще опенсурсное, проблем с ним особенных нет. И в pip я закинул релиз очень давно, так что все нормальные люди (у кого linux) просто набирают ‘pip install rumboot-tools’ и все «просто работает» ™ Почему же это не прокатывает в Windows?

Как оказалось, есть несколько зависимостей (Например, netifaces) которые pip при установке на windows будет собирать из исходников. А для этого потребуется Visual Studio Build Tools. А это 6+GB для выкачки из интернета. А так как некоторые потребители сидят за прокси ограничивающим скорость (чтобы не было соблазна смотреть порнуху в офисе!) то и выкачать столько является проблемой. До кучи эффективные менеджеры из MS с гоблинским чувством прекрасного, тягой к садомазохизму и отсутствием QA, запихнули ссылку на скачку в самую задницу страницы, а предлагают скачать не дистрибутив, а установщик, который сам тянет файлы из интернета и не всегда подхватывает настройки прокси. В общем, из нескольких человек «простых пользователей», ставших подопытными кроликами, меньше половины даже просто нашли ссылку на скачку, а самые упорные застряли на настройке прокси. И после этого M$ утверждает в рекламе, что Linux — не дружественная пользователю система.

Пробуем venv (Не прокатило)

А что если сделать venv, заархивировать и отгрузить? Не сработало. Venv прописывает абсолютные пути к установленному питону, и выходит чехарда с версиями и путями установки. Получившаяся система будет хрупкой и требовать строго определенной версии питона в системе по строго определенному пути. А если вспомнить, что виндузятники до сих пор страдают от необходимости различать 32 и 64 бит программы… А так как сама программа, это просто набор инструментов для работы из командной строки, то пользователю еще надо будет прописать и PATH!

PyInstaller (Точно не то решение, которое мы ищем)

С ним я мучался долго и не все документировал. Потому скажу просто — не заработало. Опять, как и в случае с venv нужна строго определенная версия питона, питон он с собой не пакет. К сожалению, питон оно с собой не заворачивает. К тому же потребуется писать, поддерживать и тестировать manifest для pyinstaller’а.

Стэндэлон сборка питона (Почему бы и нет?)

Идея красивая. Взять собранный питон, без всяких установщиков. Вкорячить ему нужные пакеты и запаковать для пользователей. Но не все так просто. У такого питона нет pip’а из коробки (Можно добавить, но официально не поддерживается). Самое дуракоскойкое(tm) решение, так как мы все отгружаем в одном архиве. Но собрать такой пакет непросто. Даже после установки pip’а в таком вот питоне нет хэдеров и собрать нативные расширения не получится. И потом все равно придется делать свой установщик.

WheelHouse (Серебряная пуля!)

После изрядного количества времени убитого в весьма некомфортной для работы среде и убогой командной строке cmd, я нашел, что в питоне оказывается есть простое и красивое решение проблемы. Может быть настолько очевидное, что его даже не обсуждали на стэковерфлоу и других технокурилках. pip может собрать так называемые ‘wheels’ (колеса? Скорее всего имелить в виду «кольца», в которые укладывается змея). Это бинарные пакеты! И часть того, что прилетает из pip уже является собранными wheels’ами, но у части моих зависимостей собранной под винду версии не было, отсюда и проблемы.

Еще лучше — pip может по щелчку пальцев собрать wheel’ы для твоего пакета и всех зависимостей! Просто набираем в директории проекта и «откидываемся на спинку табуретки», как во время установки Windows 98 в детстве.

pip wheel .

Результат жизнедеятельности — пачка wheel’ов ! Теперь надо это проделать для разных версий питона, которые поддерживает приложение (у меня это 3.7, 3.8, 3.9) и для 32 и 64 bit версий. И сгенерить орочий install.cmd который «накатит все эти колеса в систему». Дальше в архив и отгружаем. Звучит как задача для CI.

Такой набор файлов называется ‘wheelhouse’ у матерых питонистов. И еще есть нюанс при их установке. Так как зависимости мы все обработали, когда генерировали это все хозяйство, то надо сказать pip’у чтобы он не пытался что-то скачивать из интернета (—no-index) и не пытался разрешить зависимости (—no-deps) (Иначе придется генерировать список для установке в порядке зависимостей).

В итоге install.cmd скрипт будет выглядеть примерно так:

pip install --no-index --no-deps pkg1.wheel
pip install --no-index --no-deps pkg2.wheel
pip install --no-index --no-deps pkg3.wheel
pip install --no-index --no-deps pkg4.wheel
...

Ставить можно как глобально (в PATH ничего не надо добавлять, оно и так туда попадет) или в venv (в PATH добавит пользователь). И VS Build Tools больше не нужны. Осталось только настроить CI.

Для винды я выбрал appveyor. Он все чаще встречается для windows-проектов. «Visual Studio 2019» образ уже содержал все нужные версии питона под 32 и 64 бита. Немного магии с деплойментом и на каждый тег собираются zip’ы под все версии питона и прикрепляются к странице релизов на github. PROFIT!

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

Пример

Кому интересно, проект можно посмотреть тут rumboot-tools.

2 thoughts on “Распространяем python-приложения на Windows (и разбираемся с проблемами)

  1. Добрый день!
    Очень полезная была информация в начале статье, но конец будто обрезан. Вы разрекламировали эти wheels. Но как их создавать не сообщили. Можно догадаться, что устанавливать пользователь должен wheels, однако теперь надо понять как разработчику их получить сперва.

    1. Там есть ссылка на полный пример ci, да и создается оно одной командой ‘pip wheel .’, которая указана в посте. Тут даже и не знаю, чего больше можно описать.

Добавить комментарий для ncrmntОтменить ответ

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