Python Дайджест: как обновиться с Python 3.4 до Python 3.11, если pip уже сломан
- среда, 1 февраля 2023 г. в 00:54:47
Python Дайджест собирает IT-новости уже 9 лет, рассказывает о концепциях, проектах, релизах. Кодовая база за это время мало изменилась и уже деградировала. Более 5 лет не хватало сил и времени, чтобы привести проект в актуальное состояние. Django с 1.9 обновилась уже до 4.1 версии, Python 3.4 не актуален, да даже обновить пакет через pip не получается, потому что сломан.
В 4 частях расскажу от первого лица, как 9-летний проект из состояния outdated вернулся в actual состояние и снова набрал 100 баллов в PageSpeed.
Начну с обновления до актуального Python и Django.
Python Дайджест — это open source проект про Python, написанный на Python. В следующем году исполнится 10 лет как собираются, вычищаются, изучаются материалы и собираются дайджесты.
Проект был создан разработчиками и для разработчиков. Хотелось знать актуальные подходы к разработке, библиотеки, обновления важных библиотек, узнавать, что теперь стало стандартом. И с того времени мало что поменялось. И все также я использую этот ресурс, чтобы быть «в курсе», только теперь не для себя, а для команд, с которыми работаю.
pip freeze
.3.6 — реперная точка, потому что там появились f-string. Эту функциональность нельзя включить через какой-нибудь __future__
flag на более старых версиях. При этом свежие версии библиотек почти всегда используют f-string.
poetry
для управления ими.Для начала объединил текущую мастер-ветку с актуальным серверным кодом:
tar.gz
и перенес код с сервера на локальную машину с помощью scp
.meld
(инструмент для визуального diff) просмотрел изменения и объединил их.При объединении двух версий кодовых баз стоит внимательнее смотреть на:
У меня в системе стоит Python 3.10, что много выше, чем Python 3.4, который требуется для запуска приложения.
К счастью, есть pyenv, который позволяет установить любую версию python рядом с основной.
Это так я думал, но при выполнении команды pyenv intall 3.4
получил ошибку Missing the OpenSSL lib?. Даже инструкция про это есть.
Из инструкции и Pull Request становится ясно, что за время с Python 3.4 OpenSSL обновился с 1.11 до 3.0 (перепрыгнув несколько версий) и просто так на современном дистрибутиве его не поставить. Инструкция предлагает попробовать с системным OpenSSL версии 3.0, вместо 1.11, сделать downgrade версии, через brew на Ubuntu поставить нужную версию OpenSSL.
Ничего не дало плодов. Мне нужен был 3.4 и 3.6 Python, только пока зависимости обновляю, и поднимать полноценную виртуалку не хотелось. Поэтому решил пойти по другому пути.
Если нужен какой-то софт, который тяжело поставить/не хочется ставить в систему, то что берем? Конечно, же контейнеры. В моем случае это Docker.
Контейнеры предоставляют условно изолированную среду внутри родительской операционной системы. Можно описать образ контейнера в файле Dockerfile
со всем необходимым, загрузить на Docker Hub, а затем запускать единообразным способом на разных машинах.
В Docker Hub хранятся настолько древние образы, что можно удивляться для кого они. Вот для таких проектов, которые много лет работали и не требовали критических изменений.
Составил Dockerfile с Python 3.4, который умеет стягивать зависимости из папки проекта и устанавливать их. Вуаля! Теперь можно работать с зависимостями. А если указывать команду для запуска контейнера через docker compose (внутри dev ужас), будет совсем приятно и не надо будет пересобирать слишком часто.
На этом шаге стало ясно, что проект получится актуализировать.
Есть контейнер с Python 3.4. Теперь нужно получить актуальный серверный requirements.txt
. Как писал в начале — pip был сломан из-за ручного обновления (python setup.py install
для pip), но не беда — можно из интерпретатора достать.
import module_name
help(module_name)
И оттуда вычитать версию пакета (или просто grep
'ом парсить из venv папки).
Это нужно было сделать для всех критических пакетов, чтобы, когда будет обновление зависимостей через poetry, получили рабочее приложение.
Немного про менеджеры зависимостей.
На практике я проходил по пути от простого pip install
, затем перешел к requirements.txt
, где были описаны пакеты, затем для управления зависимостей использовал pip-tools
(тогда poetry еще тестировался), а уже затем стал использовать poetry
:
requirements.txt
— текстовый файл, в котором по строчкам перечисляются пакеты и версии для них. Первый общеупотребимый подход по описанию зависимостей.pip-tools
— набор утилит, которые позволяют задать для основных зависимостей версии, а версии для остальных зависимостей вычислить автоматически. Это такой переходный инструмент от состояния «не фиксируем версии» к «фиксируем основное, а остальное не знаем надо ли». Зачастую работает, но бывает получается битое окружение.poetry
— это текущий стандарт управления зависимостями. Позволяет уже не бояться за окружение (зачастую) и вычислять версии зависимости так, чтобы все пакеты были точно согласованы. Вероятно следующий будет pdm, а пока «стандарт» это poetry
.
Pipenv
сPipfile.lock
тоже использовал для управления зависимостями, хотя его мощь именно в создании всего dev окружения, а не только установка пакетов.
Image: Alice Lang, alicelang-creations@outlook.fr
Запуская через docker compose контейнер с Python 3.4, я начал приводить в порядок requirements.txt
: указал актуальные версии с сервера, дописал недостающие в файл.
Это позволило запустить pip-tools
(а точнее, pip-compile
) и актуализировать все остальные зависимости.
Поставил poetry
и последовательно добавил все пакеты в проект. Получил lock файл с хэшами пакетов. Фуф, теперь можно обновлять зависимости дальше — через poetry add "package_name<=version"
Обычно для пакетов назначают версию: «не обновляй выше текущей версии», однако, для массового обновления, где ручным образом проверяются, стоит ставить «меньше, равно». Уже после обновления можно заменить >= на ^
Конечно же, за 5 лет без обновлений ряд пакетов устарел, что-то умерло, какие-то пакеты переименовались и преобразовались в новые.
Перед каждым обновлением изучал, что я могу удалить из устаревших зависимостей, какие модули стали дублировать функциональность.
Требовалось ходить по пакетам, смотреть их Changelog и принимать решение.
Крупные пакеты типаlxml
,pandas
,numpy
приходилось по несколько раз обновлять, а затем снижать версию обратно. Не всегда потребители этих библиотек учитывают изменения в API.
Дальше было несколько итераций обновлений согласно таблицы совместимости Python и Django версий
from django.urls import path
для описания urls.py
on_delete=
для ForeignKey
/OneToOneField
полей моделейMIDDLEWARE_CLASSES
на MIDDLEWARE
f-string
from django.utils.six import text_type
poetry
(основная, для разработки, для тестов)from django.utils.translation import ugettext_lazy
-> gettext_lazy
Собирал образ с новым сочетанием зависимостей, прогонял тесты, удалял/добавлял пакеты, модифицировал код под версию Django, учитывая deprecations, обновлял зависимости, экспортировал новые зависимости. И так по кругу.
По итогу был получен образ с Python 3.11 + Django 4.1, который легко было запустить вне контейнера.
Через pyenv
было поднято окружение с Python 3.11, прогнаны тесты еще раз.
Теперь можно запускать проект на актуальных операционных системах.
Вы прочитали 1 из 4 часть цикла статей про обновление проекта до актуальных технологий. Для себя сделал такие выводы:
pyenv
не всегда удается развернуть окружение. Для этого можно использовать Docker контейнеры. Собирать образ, поднимать контейнер с синхронизированной папкой исходного кода, из контейнера запускать pip install
и так проводить процедуру обновления.poetry
(даже по схеме requirements.txt
-> pip-tools
-> poetry
) заметно упрощается поддержка зависимостей. Poetry
в пару команд позволяет выбирать актуальные зависимости для другой версии python, и сами зависимости держать в порядке.P.S. Актуализация существующего проекта весьма затратна по времени. Обращайтесь ко мне, axsapronov, если вам требуется сделать это.
НЛО прилетело и оставило здесь промокод для читателей нашего блога:
— 15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.