Как установить зависимости python из файла

Обновлено: 04.07.2024

P ipenv — менеджер зависимостей для Python-проектов. С его помощью можно создавать виртуальные среды и управлять зависимостями приложений. Pipenv решает ряд проблем, которые возникали при использовании pip, virtualenv и requirements.txt.

Данный инструмент аналогичен npm у NodeJS, или composer у PHP, и является официально рекомендуемым менеджером зависимостей для Python . Подробнее о том, кому он будет полезен и как им пользоваться, рассмотрим ниже.

Чем хорош Pipenv

Рано или поздно, каждый разработчик сталкивается с проблемой контроля версий пакетов pip и настройкой виртуального окружения. С помощью Pipenv вы можете:

  • Управлять окружениями ( env );
  • Управлять пакетами: устанавливать, удалять, обновлять ( pip );
  • Устанавливать детерминированный набор пакетов ( Pipfile.lock ).

Можно забыть про pip и virtualenv

Вам больше не нужно использовать pip и virtualenv по отдельности. В pipenv этот функционал реализован "из коробки".

Requirements.txt больше не нужен

Для своей работы менеджер использует 2 файла: Pipfile (по сути замена requirements.txt) и Pipfile.lock (связывает версии пакетов, тем самым обеспечивая дополнительную безопасность).

Когда вы запускаете проект с Pipenv, он автоматически создает виртуальную среду для текущего проекта, даже если вы еще не используете ее. Pipenv управляет зависимостями, отказавшись от привычного requirements.txt , и заменяя его на новый документ под названием Pipfile . Когда вы устанавливаете библиотеку с помощью Pipenv, файл Pipfile для проекта автоматически обновляется с указанием сведений об этой установке, включая информацию о версии, расположение хранилища Git, путь к файлу и другую информацию.

Пример файла Pipfile :

Ваше приложение может зависеть от конкретной версии библиотеки, а эта библиотека может зависеть от конкретной версии другой библиотеки. Если производить настройку вручную, во всем этом очень просто запутаться 🤷. Pipenv создан, чтобы облегчить эту задачу. Он отслеживает дерево взаимозависимостей вашего приложения в файле с именем Pipfile.lock В свою очередь, Pipfile.lock также проверяет, используются ли корректные версии зависимостей.

Пример файла Pipfile.lock :

Pipenv удобен, когда над проектом работают несколько разработчиков. Рассмотрим простой пример — компания ведет разработку своего корпоративного сайта. Мария работает над вкладкой "Отчеты", Иван — над вкладкой "Чат".

  • Для того чтобы отчеты создавались быстрее, Мария решает обновить некоторые питон-библиотеки.
  • В течение 2-х дней она разрабатывает новый функционал для отчетов.
  • Мария фиксирует изменения в git репозитории, но забывает запустить pip freeze . Файл requirements.txt остается в репозитории со старыми версиями библиотек.
  • Иван затягивает из репозитория изменения Марии, и внезапно выясняется, что его вкладка "Чат" стала выпадать с ошибкой.
  • Помимо этого, CI сборка тоже сломалась 😢

Требуется время, чтобы понять, что проблема в файле requirements.txt , где находятся старые версии библиотек.

Если бы Иван и Мария использовали Pipenv, Pipfile был бы автоматически обновлен и включен в коммит Марии. Они бы сэкономили время и завершили свой продукт быстрее. Вот что делает Pipenv таким важным.

Возможность создавать собственные шорткаты

Pipenv позволяет создавать собственные шорткаты (сокращения) в секции [scripts] файла Pipfile :

Теперь в консоли вы можете вызвать шорткат командой pipenv run print_hello

Автоматизация рутинных задач

Больше не придется тратить время на выполнение рутинных задач, выискивая причины отсутствия синхронизации и возникновения ошибок в версиях. Всю рутинную работу pipenv берет на себя:

  • автоматически генерирует Pipfile ;
  • автоматически удаляет/добавляет записи в Pipfile при установке/удалении пакетов;
  • автоматически создает virtualenv;
  • автоматически подгружает данные из .env файлов и т.д.

Установка

Самый простой вариант — установка с помощью pip.

Для Linux и MacOS есть альтернативный способ установки:

brew install pipenv

sudo apt install pipenv

sudo dnf install pipenv

pkg install py36-pipenv

После установки, вы можете фактически забыть о pip — pipenv по сути заменяет pip и virtualenv.

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

Рассмотрим простой пример использования pipenv.

Создаем виртуальную среду

Для инициализации виртуальной среды Python 3, выполните команду:

Если виртуальной среды еще не существует, она будет создана.

💭 Также вы можете принудительно создать среду Python 3 или Python 2. Для этого нужно выполнить команды pipenv --three или pipenv --two .

Устанавливаем пакеты

Далее можно установить сторонний пакет. Существует 3 варианта установки:

pipenv install scrapy

Установится последняя версия пакета. При этом в Pipfile добавится запись scrapy = "*"

Установятся все пакеты из Pipfile и обновится Pipfile.lock

Установятся все пакеты из Pipfile.lock

Запускаем скрипты

Запустить python-скрипты можно несколькими способами:

pipenv run python script-name.py

Настройка pipenv в PyCharm

Процесс настройки pipenv в PyCharm:

  1. В настройках откройте вкладку " Project Interpreter " - File > Settings > Project: ProjectName > Project Interpreter.
  2. Нажмите на шестеренку рядом с выпадающим списком и выберите " Add ".
  3. В списке слева выберите " Pipenv Environment ".
  4. Далее вы можете создать новое окружение " New environment " или использовать существующее " Existing environment ".

После того как все шаги выполнены, для текущего проекта устанавливается новая среда pipenv и устанавливаются пакеты, перечисленные в Pipfile.

Если вы открываете какой-либо проект с добавленным файлом Pipfile, но в нем не настроен интерпретатор, PyCharm предложит вам использовать среду Pipenv. Если вы выберете эту опцию, PyCharm автоматически установит для вас pipenv.

Команды pipenv

  • pipenv shell — активация виртуального окружения;
  • exit — выход из виртуального окружения;
  • pipenv check — проверка на наличие уязвимостей безопасности.
  • pipenv install — установка всех пакетов из Pipfile ;
  • pipenv install scrapy==1.8.0 — установит фиксированную версию пакета;
  • pipenv install selenium --dev — установит selenium как пакет только для разработки;
  • pipenv install --system — установка зависимостей в родительскую систему;
  • pipenv uninstall scrapy — удаление пакета;
  • pipenv uninstall --all — удаление всех установленных пакетов в виртуальной среде.
  • pipenv lock — генерация Pipfile.lock ;
  • pipenv sync — установка пакетов из Pipfile.lock ;
  • pipenv clean — удаление из virtualenv всех пакетов, которых нет в Pipfile.lock .
  • pipenv --where — путь до текущий проект;
  • pipenv --venv — путь до virtualenv;
  • pipenv --py — путь до интерпретатора;
  • pipenv graph — отображение графа зависимостей.

Pipenv и Docker

pipenv lock --requirements > requirements.txt

Плюс в том, что Dockerfile не нужно ничего знать о pipenv. Иначе, это потребовало бы обновлять файл require.txt при каждом обновлении Pipfile.lock .

В качестве альтернативы можно выполнить экспорт в самой сборке:

FROM python:3.7 RUN pip install pipenv COPY Pipfile* /tmp RUN cd /tmp && pipenv lock --requirements > requirements.txt RUN pip install -r /tmp/requirements.txt COPY . /tmp/myapp RUN pip install /tmp/myapp CMD flask run exampleapp:app

pipenv install --deploy --system

--deploy — pipenv выдаст ошибку если Pipfile.lock устарел, вместо того, чтобы сгенерировать новый Pipfile.lock файл.

--system — устанавливать зависимости в родительскую систему.

Рассмотрим пример Dockerfile для развертывания Flask приложения:

FROM python:3.7 RUN pip3 install pipenv WORKDIR /usr/src/app COPY Pipfile ./ COPY Pipfile.lock ./ RUN set -ex && pipenv install --deploy --system COPY . . EXPOSE 8000 CMD [ "gunicorn", "-b0.0.0.0:8000", "wsgi:app" ]

Конфигурирование pipenv

Pipenv дает возможность конфигурировать свое поведение с помощью переменных окружения ( Environment Variables ). Просто создайте переменную и pipenv обнаружит её. Вот некоторые их них:

  • PIPENV_VENV_IN_PROJECT — создаст виртуальное окружение .venv в папке с проектом;
  • PIPENV_YES — автоматически соглашаться со всеми диалогами;
  • PIPENV_DONT_LOAD_ENV — не загружать файл .env;
  • PIPENV_INSTALL_TIMEOUT — максимальное время ожидания установки пакета (сек.);
  • PIPENV_MAX_SUBPROCESS — количество подпроцессов, используемых во время установки;
  • PIPENV_PIPFILE — путь до файла Pipfile .

Полный список переменных можно посмотреть в официальной документации pipenv, в разделе " Configuration With Environment Variables ".

Стоит ли использовать Pipenv?

Определенно да! 🎉 Pipenv сведет всю работу по управлению пакетами и виртуальным окружением в одну консоль, решит проблему с версионированием пакетов и добавит новый, весьма приятный функционал.

Недавно я решил, что пора наконец-то разобраться в теме управления зависимостями в моих Python проектах и начал искать решение, которое бы меня полностью устроивало. Я поэкспериментировал с pipenv, проштудировал документацию к poetry, почитал другие статьи по теме. К сожалению, идеального решения я так и не нашел. В результате, я изобрел новый велосипед свой подход, который и предлагаю обсудить под катом.

Проблема

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

В рамках моей работы чаще всего я использую Python в двух целях: это либо анализ данных и машинное обучение используя блокноты Jupyter, либо небольшие Python скрипты, которые каким-то образом подготавливают данные. Хочу отметить, что я не занимаюсь созданием пакетов и их публикацией в Pypi (поэтому не акцентирую внимание на этом процессе в этой статье).

Очень часто мне требуется запускать скрипты или блокноты, которые были созданы довольно давно. Поэтому у меня возникла необходимость каким-то образом фиксировать версии зависимостей и запускать скрипты и блокноты в виртуальном окружении. С другой стороны, иногда в новой версии какой-либо библиотеки может появиться функциональность, которая позволит улучшить результаты старого блокнота или скрипта. Например, в scikit-learn (библиотека для машинного обучения) могут добавить имплементацию нового алгоритма, который отлично подходит для моего случая.

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

Исходя из этих предпосылок, у меня сложились следующие требования для управления зависимостями:

  1. У меня должна быть возможность разделять центральные зависимости (необходимые для запуска скрипта) и зависимости необходимые только для разработки.
  2. Я хочу указывать центральные зависимости без привязки к конкретной версии библиотеки. Таким образом, я смогу легко обновлять зависимости. С другой стороны, у меня должна быть возможность зафиксировать версии библиотек, чтобы полностью повторить мое виртуальное окружение.
  3. Один и тот же подход должен одинаково хорошо работать и для скриптов и для блокнотов.

Канонический подход по управлению зависимостями, когда создается отдельное виртуальное окружение для проекта и когда версии всех зависимостей фиксируются (используя pip freeze > requirements.txt ) в requirements.txt, не работает исходя из моих требований. Во-первых, он не позволяет разделить центральные и зависимости необходимые только для разработки. Во-вторых, в этом случае requirements.txt содержит все зависимости и их подзависимости, поэтому искать версию определенной библиотеки становится проблематичным.

Исходя из этих требований, оптимальным решением казалось использование pipenv (вот, например, статья о том, как использовать этот инструмент). Но когда я начал экспериментировать с ним, я выяснил, что у него есть несколько недостатков. Например, когда я использовал его для установки библиотек, он иногда полностью зависал или работал на редкость медленно. Поэтому после нескольких неудачных попыток, я решил дальше не продолжать с ним, хотя он идеально подходит исходя из моих требований. Poetry же не работает для управления зависимостями для блокнотов.

Решение

Прежде всего, хочу отметить, что я в качестве операционной системы использую (k)Ubuntu 18.04. Если у вас другая операционная система, возможно потребуется адаптация моего подхода. Если вы адаптируете этот подход под другую операционку, то было бы здорово, если бы вы поделились им в комментариях.

Для решение этой проблемы, я применяю следующий подход. Во-первых, я разделил центральные и зависимости для разработки. При установке я записываю имена зависимостей в два разных файла: requirements.txt содержит центральные зависимости, в то время как requirements-dev.txt хранит зависимости необходимые для разработки. Чтобы автоматизировать этот процесс, я написал bash функцию pip-install .

Чаще всего, я вызываю эту функцию следующим образом: pip-install scikit-learn или pip-install --dev pylint . В первом случае, эта функция устанавливает пакет scikit-learn используя pip и записывает имя пакета (которое вы написали) в файл requirements.txt. Во втором случае, имя пакета записывается в файл requirements-dev.txt. Стоит отметить, что так как эта функция используется при разработке, то я не указываю версию библиотеки, которую надо установить (в этом случае устанавливается последняя доступная версия). В последующем, в этом файле можно добавить ограничения на версию библиотеки вручную.

Когда мне требуется зафиксировать версии библиотек, я вызываю функцию pip-freeze . pip-freeze выбирает все зависимости из файла requirements.txt, фиксирует их версии и записывает результат в requirements.lock файл. После этого, мы можете легко восстановить свое виртуальное окружение на новой машине используя команду pip install -r requirements.lock . Команда pip-freeze --dev проделывает тот же фокус, только с зависимостями из requirements-dev.txt.

Таким образом, в репозитории вместе с проектом я храню 4 файла: requirements.txt, requirements-dev.txt, requirements.lock и requirements-dev.lock.

Исходный код этих двух функций хранится у меня в файле (Всегда проверяйте исходники. ). Вы можете скопировать его в директорию

/.bash/ , и чтобы сделать эти функции доступными у себя, добавить следующие строчки к себе в .bashrc :

Заключение

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

Если вам интересно узнать о том, как я настраиваю свое Python окружение, то я написал очень длинную статью (на английском) по этой теме у себя в блоге.

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 :

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

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

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

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

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

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

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

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

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

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

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

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

    Бонус

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

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

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

    Данная статья является пошаговым введением в базовые навыки управления пакетами Python с помощью команды pip. В ней будут освещены следующие моменты:

    • Поиск пакетов
    • На какую информацию следует обратить внимание в пакете
    • Установка пакетов
    • Визуализация установленных пакетов
    • Установка пакетов из файла requirements.txt
    • Удаление пакетов с помощью pip

    Поиск пакетов Python

    Рассмотрим случай использования пакета emoji в качестве примера. Для поиска Python пакетов, связанных с emoji, перейдём на веб сайт PyPi и через окно поиска в правом верхнем углу страницы поищем emoji.

    Обратите внимание на колонку «Weight*» в середине таблицы. Это ключевая информация. Значение веса – это специфический рейтинг, который сайт рассчитывает для каждого пакета, чтобы ранжировать результаты поиска.

    Согласно самому сайту, то рейтинг вычисляется на основе полей: имя, сводка, ключевые слова, описание, автор, мейнтейнер. Означает ли что найден лучший пакет? Не обязательно. Несмотря на необычность, сторонние пакеты своим присутствием могут затенять emoji.

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

    В какой среде будет работать emoji? Приложение на основе терминала или, возможно, веб-приложение Django? Если нужно отобразить emoji в веб-приложении django, то лучше воспользоваться пакетом django-emoji. Для нашего случая предпочтительным вариантом является emoji для Python приложения командной строки.

    На что нужно обратить внимание?

    Далее приведены характеристики хорошего пакета Python:

    Достойная документация: прочитав её, сразу становится понятно, соответствует ли пакет потребности или нет;

    Зрелость и стабильность: если он существует уже продолжительное время, а также последними версиями;

    Количество контрибьюторов: востребованные пакеты (особенно сложные), как правило, контрибьютятся большим количеством разработчиков;

    Техническое обслуживание: он регулярно проходит техническое обслуживание.

    Не стоит слишком полагаться на статус разработки, указанный для каждого пакета, то есть пакет может иметь баллы стабильности, например, 4 - Beta или 5 - Production / Stable. Эта классификация заполняется самим разработчиком и не обязательно должна быть правдивой.

    На нашем случае документация выглядит достаточно прилично. В верхней части страницы показано графическое представление работы пакета emoji в интерпретаторе Python.

    Документация для пакета emoji также рассказывает об его установке, как внести свой вклад в разработку, а также ссылку на страницу с исходниками, что является отличным источником полезной информации о нём.

    Установка пакетов Python с помощью pip

    Предполагается, что Python уже установлен в вашей системе. Далее нужно проверить, установлен ли pip, запустив pip -version в терминале.

    Начиная с Python 3.4, pip входит в комплект поставки.

    Также рекомендуется использовать виртуальную среду для управление рабочим процессом разработки и упрощения работы над несколькими проектами одновременно без возникновения конфликтов в их зависимостях.

    Отличное вариант для начала изучения консольной программы - это запустить её без каких-либо опций в терминале.

    Рассмотрим команду freeze, которая является ключевой в разрешении зависимостей. Запуск pip freeze отображает список всех установленных пакетов Python. Если выполнить с инструкцию с активной виртуальной средой, то будет распечатан пустой список

    Для установки пакета, выполним pip install emoji в терминале. В результате будет получен следующий вывод:

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

    Конкретная версия пакета (==):

    Версия, отличная от указанной (! =):

    Версия, равная или превышающая конкретную версию (> =):

    Версия пакета в указанном диапазоне (> = X.Y.T, <= X.Y.Z):

    Как правило, наиболее полезным спецификатором является == для установки конкретной версии пакета. Если не будет ограничения, то будет установлена последняя версия пакета.

    Запустим pip freeze после установки пакета emoji.

    Теперь pip freeze отображает пакет emoji как установленная зависимость с определенным номером версии.

    Получение списка установленных Python пакетов

    Для выгрузки установленных пакетов в файл requirements.txt выполним программу pip freeze с перенаправлением выходного потока в файл.

    Визуализация установленных пакетов

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

    После установки пакета запустим процесс freeze, чтобы удостовериться в его установки:

    Теперь запустим pipdeptree в терминале, чтобы узнать, что он делает.

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

    Также замечаем другие пакеты, которые отсутствуют в списке freeze – pip и setuptools. Причина в том, что по умолчанию pip freeze не перечисляет пакеты, от которых зависит сам pip.

    Теперь запустим pip freeze -all для отображения всех установленных пакетов:

    Ещё одно преимущество использования pipdeptree заключается в том, что она предупреждает нас о конфликтующих зависимостях, в том числе о циклических (когда пакеты зависят друг от друга), но это очень редко встречающийся случай.

    Установка пакетов Python из файла requirements.txt

    Если есть файл requirements.txt, то можно установить все перечисленные там пакеты, выполнив следующую команду:

    Это очень удобно, когда нужно реплицировать виртуальные среды на другие компьютеры.

    Удаление пакетов Python с помощью Pip

    Удаление отдельных пакетов Вы можете сделать это, запустив, например, pip uninstall alembic.

    Также допустимо удаление нескольких пакетов сразу, используя следующий синтаксис командной строки:

    Другим вариантом является чтение списка пакетов для удаления из файла requirements.txt. Как и у его установочного варианта, если есть файл requirements.txt, то можно удалить все перечисленные там пакеты аналогично:

    Если попытаться выполнить эту инструкцию программа покажет множество предупреждений и спросит продолжать несколько раз (по одному разу для каждого пакета), на который нужно ответить y. Чтобы избежать этого, используя флаг -y:

    Читайте также: