Управление окружением Python c Pipenv

  • Tutorial

Привет, мой друг!


Предположу, что для управления Python окружением в вашем проекте до сих пор используется pip и virtualenv.


Если это так, то позвольте рассказать о таком инструменте, как Pipenv.


Pipenv — это современный инструмент для управления рабочим окружением в Python.


Основные возможности pipenv:


  • Создание и управление виртуальным окружением
  • Синхронизация пакетов в Pipfile при установке и удалении пакетов
  • Автоматическая подгрузка переменных окружения из .env файла

В качестве показательного примера сравним использование pip и virtualenv с pipenv для создания виртуального окружения:


  1. pip и virtualenv


    $ virtualenv venv
    $ source venv/bin/activte
    $ pip install Flask gunicorn
    $ pip freeze > requirements.txt

  2. pipenv


    $ pipenv install Flask gunicorn


Начало работы


Установим последнюю версию pipenv:


$ pip install pipenv

Управление рабочим окружением


Перейдем в каталог с Python проектом и создадим виртуальное окружение указав версию интерпретатор:


$ cd yourproject
$ pipenv --python 3.7

Команда автоматически создаст новое виртуальное окружение для вашего проекта, если он еще не существует.


Активировать виртуальное окружение проекта можно выполнив команду shell:


$ pipenv shell

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


$ exit

Управление зависимостями приложения


Для установки пакетов воспользуемся командой install:


$ pipenv install Flask

Pipenv установит последнюю версию пакета Flask и автоматически добавит его в Pipfile.


При установке можем задать конкретную версию пакета:


$ pipenv install Flask==1.0.2

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


При указании флага --dev, пакет будет установлен как часть среды разработки:


$ pipenv install pytest --dev

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


$ pipenv install --dev

Для удаление пакетов существует команда uninstall:


$ pipenv uninstall Flask

Сведения об установленных пакетах и их зависимостях хранятся в файле Pipfile.lock, который генерируется автоматически и не должен быть изменен пользователем.


Запуск исходного кода


Существует возможность запуска исходного кода внутри оболочки virtualenv:


$ pipenv run python yourapplication.py

При наличии файла .env команды $ pipenv shell и $ pipenv run, автоматически подгрузят из него переменные окружения:


$ cat .env
DEBUG=1

$ echo $DEBUG
1

Развертывание приложения


Pipenv позволяет устанавливать зависимости в родительскую систему при указании флага --system:


$ pipenv install --system

Это полезно при развертывания приложений в Docker.


При указании флага --deploy — pipenv выдаст ошибку, если Pipfile.lock устарел или версия Python не соответсвует указанной.


Пример Dockerfile для работы с pipenv:


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 . .

Пример приложения на Flask с использованием возможностей Pipenv: github.com/fdhadzh/flask-pipenv-example.

Поделиться публикацией

Комментарии 35

    0
    А для чего заходить в шелл?
    Почему бы просто не создать окружение командой
    pipenv --python 3.7
      0

      Спасибо, поправил.

        0
        Вы так упорно лезете в шелл… а зачем? можно и без этого вполне обойтись :)
      0

      В Pipfile можно задать интерпретатор вот так:


      [requires]
      python_version = "3.5"

      Почему разработчики pipenv не хотят сделать возможность задавать несколько версий Python?
      Есть вот такие закрытые issue, например, где они довольно резки и категоричны:
      https://github.com/pypa/pipenv/issues/1050


      Хотя в том же PEP-508 на котором основана эта разработка явно прописано, что можно задавать несколько версий
      https://www.python.org/dev/peps/pep-0508/


      Можно же создавать venv и Pipfile.lock для разных версий интерпретатора. А как сейчас указать в Pipfile, что мы поддерживаем, скажем Python 2.7 и >=3.4? Или я и все эти люди из issue что-то не понимаем?


      Также они [разработчики] почему-то решили, что разделение окружений на dev и default хватит всем, но, очевидно, это не так. Мне, например, как минимум нужны ещё testing и doc. И я не один такой:
      https://github.com/pypa/pipenv/issues/726
      https://github.com/pypa/pipenv/issues/2303


      Но разработчики как всегда категоричны:


      not happening. explicitly designed for just two groups.

      Смотря на всё это… а как на счёт poetry?

        0

        Да, pipenv не серебряная пуля, но удовлетворяет большинству требований типовых приложений.


        А poetry действительно заслуживает отдельного внимания. Спасибо!

        +1
        Я в Python весьма неопытный, можно очень кратко, в чем кардинальное различие между pipenv и venv+pip? Какое-нибудь офигенное удобство, или фича, которую другими решениями, можно решить только велосипедами?
          0

          Хорошая идея, спасибо.

            0

            Некоторые незначительные преимущества есть, просто они в данной статье вообще не рассмотрены. Но я использую virtualenv + fish + virtualfish, и пока для себя не вижу резона переходить на pipenv. Надо возможно поиграться с ним на каком-нибудь проекте, может быть, тогда почувствую преимущества.

            0
            Все это уже было и есть в conda. В чем преимущества?
              +2
              Основное отличие pipenv — это наличие файла Pipfile.lock, содержащего список версий всех пакетов, установленных в этом окружении, с их зависимостями + md5 сумма файла пакета.
              Это дает воспроизводимость сборки. Например, нет проблемы, когда вы протестировали свой код на CI 2 дня назад, а во время раскатки на production приехала обновленная версия какой-то из зависимостей, несовместимая с вашим кодом(несколько раз натыкался на такое в связке aiohttp — yarl).
              Наличие же md5 дает некоторую защиту от атаки MITM и внедрения вредоносного кода при установке на другое окружение.
                0
                conda умела контролировать версии установленных пакетов и проверять зависимости и до pipenv и не только не даст поставить несовместимое, но и подберет такой полностью совместимый набор версий для всех пакетов environment-а.
                  0

                  в моем случае в requirements.txt был указан только aiohttp, который по зависимостям подтянул обратно несовместимую версию yarl.


                  в случае с pipenv при выполнении команды


                  pipenv install aiohttp==2

                  генерируется Pipfile.lock, в котором прописан aiohttp == 2.0.5, yarl == 0.9.3(версии указаны для примера). На этой установке прогоняются тесты и в production пойдут именно эти версии пакетов.


                  в случае с обычными requirements.txt после установки каждого пакета надо руками запускать freeze и, возможно, очищать его от каких-то локальных пакетов.
                  как это работает в conda с его environment.yml я не смог найти, буду признателен за ссылку.

                    0

                    А если в вашей системе есть другой пакет, которому нужна другая версия yarl, pipenv эту ситуацию разрулит?

                  0

                  Мне вот правда интересно, были ли в реальности случаи осуществления MITM по отношению к пакетной системе Питона? Я понимаю, что если даже ничего такого не было, это не значит, что ничего такого произойти не может. Но с таким же успехом вы можете изначально поставить подмененный пакет, рассчитать для него хэш) Такая защита выглядит странно. Для исключения подмены пакетов уже давно придумана pgp подпись)

                    0

                    не скажу за питон, но в целом проводятся атаки на пакетные менеджеры, например, на npm.


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

                    0

                    Я для фиксации версий есть pip freeze. Так что мне совсем непонятны преимущества данной тулзы)

                      0

                      pip freeze не делает фиксации версий, он просто показывает версии пакетов, установленных в данном окружении.
                      там могут быть указаны системные пакеты, если, например, окружение собрано с флагом --system-site-packages, что в общем случае нежелательно и создает дополнительную головную боль.
                      pipenv решает эту проблему в полуавтоматическом режиме.

                        0

                        pip freeze > requirements.txt
                        pip install -r requirements.txt
                        Первая команда фиксирует, вторая — инсталлирует все запиненные версии. По поводу флага, никогда не сталкивался с такой сборкой питона в рабочих проектах, мы везде испоьэльзуем виртуальное окружение, и такой проблемы не наблюдаем. Но, если у вас такая проблема есть, то, да, наверное, pipenv тут поможет

                          0

                          да понятно, просто в случае с pipenv все эти команды выполняются оболочкой за разработчика — это удобно(одна команда вместо 2) и более безопасно(про pip freeze можно, например, попросту забыть).


                          такая сборка имела смысл в доисторические времена, когда еще не было wheel, а пакеты под windows распространялись в виде exe и ставить в virtualenv их было невозможно.

                    +2
                    В статье сравнивается работа pip и pipenv на двух примерах. pip:
                    $ virtualenv venv
                    $ source venv/bin/activte
                    $ pip install Flask gunicorn
                    pipenv:
                    $ pipenv install Flask gunicorn

                    А почему pipenv показан не так?
                    $ pip install pipenv
                    $ pipenv shell
                    $ pip install Flask gunicorn

                    Я pipenv не использовал и предубеждений против него не имею, просто любопытно.
                      0

                      Для формирования файла зависимостей приложения (requirements.txt) с помощью pip и virtualenv необходимо создать и активировать виртуальное окружение, установить пакеты и "заморозить" их. При использовании pipenv нет необходимости в активации виртуального окружения, команда install создаст окружение, если оно отсутствует, установит пакеты и добавит их в Pipfile.

                        0
                        Понял, спасибо!
                        +1
                        А почему pipenv показан не так?

                        Удобство. Обо всем по порядку.


                        pip install pipenv

                        Вы единожды ставите пакет в систему и больше его не трогаете. Поэтому нет смысла указывать этот шаг при сравнении двух этих инструментов.


                        $ pipenv shell
                        $ pip install Flask gunicorn

                        А это не альтернатива.
                        shell используют, если вам нужно проделывать много манипуляций из-под этого virtualenv. Если вам нужно установить пакеты или запустить скрипт — зачем?


                        Для установки же пакетов очень удобно использовать $ pipenv install <package>, который автоматически посмотрит, есть ли в данной папке Pipfile, создано ли окружение, если нет — создаст, установит в это окружение пакеты и "запинит" зависимости.
                        pip install <package> же этого всего не сделает, даже если запускать его внутри shell. Да, он установит пакет в virtualenv, но "пинить" зависимости вам придется самим.

                          0
                          А что делать, если я хочу потестировать новый пакет, но пинить мне не надо? Обычно это поведение менеджеров по умолчанию, что npm, что pip и это вполне обоснованное решение. Если разработчик хочет зафиксировать версии пакетов, которые у него есть в о окружении и раскатить эти изменения на всех, и на прод в том числе, он должен сделать это явно. А такое поведение с фиксацией по умолчанию может сыграть злую шутку.
                            0
                            А что делать, если я хочу потестировать новый пакет, но пинить мне не надо?

                            pipenv install <package> --skip-lock


                            он должен сделать это явно

                            Тут явно делается обратное. Вы всегда хотите запинить версии. А если нет — пожалуйста, вот флаг.

                              0
                              Ну, как я уже написал, это потенциальное поле для проблем) Если я набираю команду install, я ожидаю именно install, а не pin, deploy или ещё что-нибудь бонусом) В общем, в лучших антпаттернах Питона, потому как это совсем не explicit is better than implicit.
                        0

                        Есть такая крутая штука, называется pyenv. Там вам и любая версия питона и автоматическая активация окружения при входе в нужную папку. Советую )

                          0

                          Эту "штуку" Pipenv вполне себе поддерживает.
                          А еще много других, крутых фишек. Все в одном пакете, с удобным CLI.
                          Советую более детально ознакомиться на официальном сайте проекта.


                          Проект активно развивается, но я, например, пока не перешел на него. Производительность хромает (по крайней мере на Windows), некоторые решения разработчиков в дизайне инструмента сомнительны (в Issues много интересных обсуждений).


                          Присматриваюсь к poetry, попутно используя старый добрый pip + venv.

                            +1

                            Я и не писал, что pipenv не поддерживает pyenv) Я вот ещё раз перечитал по вашей ссылке список фичей и для меня честно плюсы этого инструмента очень сомнительны по сравнению с остальными. Давайте пройдемся по каждому пункту отдельно:


                            - You no longer need to use pip and virtualenv separately. They work together.

                            Это реально проблема для разработчика? Ну поставьте pyenv, он решает эту проблему, да еще и добавляет возможность ставить любую версию питона и на базе него создавать окружения, автоматически их активировать при входе в папке, деактивировать при выходе и так далее без всяких доп. pipenv shell комманд.


                            Managing a requirements.txt file can be problematic, so Pipenv uses Pipfile and Pipfile.lock to separate abstract dependency declarations from the last tested combination.

                            Вот это должно стоять первым пунктом и пожалуй единственная стоящая фича всего проекта — разделение зависимостей от явно установленных пакетов. Но это решается и без pipenv. Может и не так элегантно) Но ставить только для этого отдельную тулзу как-то избыточно, что ли.


                            Hashes are used everywhere, always. Security. Automatically expose security vulnerabilities.

                            От установки изначально неправильного или подмененного пакета это никак не защищает.


                            Strongly encourage the use of the latest versions of dependencies to minimize security risks arising from outdated components.

                            А это вообще зло. С одной стороны, ребята пишут, что жестко пинят версии, а потом пишут, что поощряют использовать самые последние версии зависимостей. В моей практике, даже обновление зависимостей может повлечь неконтролируемое изменение поведения кода, поэтому обновлять зависимости, как и установленные пакеты, нужно очень осторожно. И лучше это делать явно, руками и поднимать версии на нужные, а не на самые последние. Поэтому это бы я записал не в преимущество, а скорее в недостаток.


                            Give you insight into your dependency graph (e.g. $ pipenv graph).

                            Эмм, ну да, полезная штука наверное. За более пятилетний опыт разработки на питоне не разу с такой проблемой не сталкивался. Но, если она реально у кого-то возникает, то да, тут без pipenv наверное не обойтись.


                            Streamline development workflow by loading .env files.

                            А включать в тулзу, которая управляет пакетами, функционал чтения и активации файлов, которые к управлению пакетами вообще не имеют никакого отношения, — по мне так моветон. Для этого есть direnv и аналоги, которые именно для этого и предназначены и работают не только для питона (я, например, использую его и для проектов на node, go и так далее). А зачем эта функция в менеджере пакетов, непонятно.

                              0
                              Ответил вам ниже, не туда отправил :(
                          –1
                          Это реально проблема для разработчика?

                          Конечно, это невероятно упрощает работу. Раньше нужно было делать несколько вещей и следить за ними самому (где создавался venv, активировал ли я его), а тут всё сделали за меня.


                          поставьте pyenv, он решает эту проблему, да еще и добавляет возможность ставить любую версию питона и на базе него создавать окружения

                          Поставить инструмент хуже, чем инструмент лучше? Странное предложение. Тем более, что pipenv умеет использовать pyenv, поэтому минусов никаких на выходе не получаем.


                          Но это решается и без pipenv. Может и не так элегантно) Но ставить только для этого отдельную тулзу как-то избыточно, что ли.

                          Нет, не избыточно. Это автоматизация рутинного процесса в инструменте, который я буду использовать каждый день. И другие разработчики тоже. А то все городят свой костыль.


                          От установки изначально неправильного или подмененного пакета это никак не защищает.

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


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

                          Они "пинят", в Pipfile.lock. А коли же вы его потеряли — из Pipfile установятся последние версии пакетов, если вы не укажете другое сами. Это уже в ответ на:


                          лучше это делать явно, руками и поднимать версии на нужные, а не на самые последние

                          включать в тулзу, которая управляет пакетами, функционал чтения и активации файлов

                          Тут я и согласен, и нет. С одной стороны — вы правы, с другой — а зачем мне использовать какой-то дополнительный пакет, если это сделает pipenv? Он просто сделает внутри окружения доступным всё что есть в .env как переменные окружения. Это даже логично звучит. Pipenv все-таки и окружением управляет. Я скорее рад этому, чем нет.




                          Я допускаю, что не весь функционал Pipenv может быть нужен всем разработчикам, многие спокойно себе живут используя другие инструменты, но в мире Питона не было удобного способа делать свою разработку удобной, как это уже давно сделано в других "мирах" (PHP, JS, Ruby, ...). Использовать его или нет исключительно ваше право, но многие разработчики очень довольны, просто дайте ему шанс. Возможно, удасться насладиться тем, что за вас все сделали и вы можете просто заняться разработкой, а не играми с окружением и зависимостями! :)

                            +1
                            Раньше нужно было делать несколько вещей и следить за ними самому (где создавался venv, активировал ли я его)

                            Насколько я понял из описания инструмента, окружение все равно надо явно активировать через pipenv shell, поэтому не понимаю, чем pipenv shell отличается от. venv/bin/activate к примеру. И там и там можно забыть активировать окружение.
                            pyenv же активирует окружение при входе в директорию проекта без всяких pipenv shell.


                            Поставить инструмент хуже, чем инструмент лучше? Странное предложение. Тем более, что pipenv умеет использовать pyenv, поэтому минусов никаких на выходе не получаем.

                            Начнем с того, что это разные инструменты) хотя их функционал может частично пересекаться. Поэтому писать, что один инструмент хуже, чем другой, хотя их сценарии и задачи отличаться, вот это действительно странно) Я лишь предложил pyenv в качестве альтернативы автоматической активации окружения.


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

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


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

                            А можно про это поподробнее?) Как использование хешей для файлов может оповестить о наличии или отсутствии уязвимостей в коде?


                            Они "пинят", в Pipfile.lock. А коли же вы его потеряли — из Pipfile установятся последние версии пакетов

                            То что они пинят, я понял) Просто непонятно тогда, что значит "Strongly encourage the use of the latest versions of dependencies"


                            Он просто сделает внутри окружения доступным всё что есть в .env

                            Ну если вы используете только питон, наверное, да, хороший вариант. Но если что-то, что выходит за рамки этого языка, то увы, тут pipenv будет только мешать этим функционалом, потому что в одном месте вы будете использовать стороннюю тулзу, а в проектах на питоне pipenv. Но, в целом, конечно, дело вкуса.
                            Вдобавок, если вы обратили внимание, то этот pipenv позиционируется разработчиками именно как менеджер среды dev окружения "Python Dev Workflow for Humans". А поэтому использовать его в проде я бы не рискнул. А при использовании его только в дев окружении теряется весь смысл, потому что на прод деплоится это будет уже по-другому.

                              –1
                              окружение все равно надо явно активировать через pipenv shell, поэтому не понимаю, чем pipenv shell отличается от. venv/bin/activate к примеру

                              Для установки пакетов НЕ нужно активировать окружение самому. Даже для запуска скриптов можно НЕ активировать окружение самому, а воспользоваться pipenv run <command>, чтобы исполнить что-нибудь из нужного окружения.


                              Я лишь предложил pyenv в качестве альтернативы

                              Начнем с того, что это разные инструменты

                              Так и запишем!


                              Еще раз. pipenv при желании расширяется возможностями pyenv. Зачем себя ограничивать pyenv, а остальные вещи делать руками или другими способами — непонятно.


                              pyenv же активирует окружение при входе в директорию проекта

                              На любой "платформе"? bash / zsh / cmd / powershell?
                              Автоматическую активацию окружения уже давно можно сделать и просто в pip, подключив нужный плагин в том же zsh. Такие же штуки есть и для pipenv.


                              Как использование хешей для файлов может оповестить о наличии или отсутствии уязвимостей в коде?

                              Никак, сори, я неправильно прочитал ваш комментарий. Я держал у себя в голове информацию об этом.


                              Просто непонятно тогда, что значит "Strongly encourage the use of the latest versions of dependencies"

                              Нет Pipfile.lock — всегда ставит последние версии пакетов, если не указано иначе.


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

                              Не совсем понимаю, как тут будет мешать pipenv. Есть проект на Python, в нем есть свой .env, pipenv его подтянул. Никто не мешает использовать остальные тулзы.


                              pipenv позиционируется разработчиками именно как менеджер среды dev окружения "Python Dev Workflow for Humans"

                              Ну, это очевидно. Вы превращаете свой неудобный процесс разработки в удобный. :)


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

                              Ничего не теряется. Даже если вы будете собирать свое приложение в Докере — вам так или иначе нужны конкретные версии пакетов, которые будут лежать в Pipfile.lock. А его уже разработчик будет создавать при помощи pipenv с великим удовольствием.

                                +1
                                >  а воспользоваться pipenv run То есть мне все команды запуска надо переделать? А если по какой то причине мне придется поменять инструмент, то менять команды запуска обратно. Ну да, весело наверное.

                                > Так и запишем!

                                Не стоит вырывать фразы из контекста. Я написал про альтернативу автоматической активации окружения, а не про управление зависимостями. Pyenv — это про разные версии интерпреторов и окружений на их базе и только. А pipenv в этом плане и жрец, и жнец, и на дуде игрец: и виртуальное окружение включит, и пакеты запинит, ещё и переменные окружения сам подгрузит, разве что пакет не собирает сразу под 3 платформы, и не деплоит их на сервера. А самое интересное, что без pip и virtualenv/venv он не работает, то есть по сути дублирует уже существующий функционал, но добавляет ещё расчет хэша, польза которого очень сомнительна, отделение зависимостей от явно установленных пакетов (похоже это единственный его плюс), ну и установку переменных окружения, которая к питону не имеет прямого отношения и тоже должна выполняться отдельными инструментами (поскольку, опять же, к питону напрямую не относится).

                                > Зачем себя ограничивать pyenv, а остальные вещи делать руками или другими способами — непонятно.

                                Ну если бы pipenv только управлял версиями и зависимостями в явном виде, то вопросов бы не было)

                                > На любой «платформе»? bash / zsh / cmd / powershell?

                                Насколько мне известно, да, поскольку вы прописываете его исполняемые файлы в PATH. Но я могу ошибаться, вам лучше ознакомиться с документацией.

                                > Нет Pipfile.lock — всегда ставит последние версии пакетов, если не указано иначе.

                                Вы так и не ответили на мой вопрос. Что значит «Strongly encourage the use of the latest versions of dependencies»? Об этом пишут разработчики инструмента на главной странице. Я лучше сначала разберусь, что это такое и как оно отразится на стабильности проектов, прежде чем использовать, тем более в проде ) Пока этот пункт мне непонятен.

                                > Никто не мешает использовать остальные тулзы.

                                Ну да, можно конечно. Только странно, что у вас переменные окружения будут выставляться 2 раза: сначала через pipenv, потом через другую тулзу, ну или наоборот, кто ж знает наверняка)) Даже не знаю, зачем вам такой костыль, но вам виднее) У всех разные запросы и задачи.
                                В заключение хочу сказать, что использование конкретного инструмента — дело сугубо индивидуальное. Но если мне нужно помимо менеджера пакетов, виртуального окружения и программы, которая подгружает переменные окружения ставить ещё инструмент, который делает всё то же самое, но не работает сам по себе ни без пакетного менеджера, ни без виртуального окружения, добавляет сомнительную функциональность, а также миграция на него и с него потребует немало времени (правка не только всех дев скриптов, но и скриптов развертывания), да ещё мне непонятны некоторые моменты в его философии, я наверное воздержусь.

                            0

                            Хороший экскурс по pipenv от Kenneth Reitz тут

                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                            Самое читаемое