Pipenv: руководство по новому инструменту упаковки Python

Pipenv: руководство по новому инструменту упаковки Python

Pipenv - это упаковочный инструмент для Python, который решает некоторые общие проблемы, связанные с типичным рабочим процессом с использованиемpip,virtualenv и старого доброгоrequirements.txt.

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

В этом руководстве рассказывается о том, какие проблемы решает Pipenv и как управлять зависимостями Python с помощью Pipenv. Кроме того, он покажет, как Pipenv соответствует предыдущим методам распределенияpackage.

Free Bonus:Click here to get access to a free 5-day class, который показывает, как избежать распространенных проблем управления зависимостями с такими инструментами, как Pip, PyPI, Virtualenv и файлами требований.

Проблемы, которые решает Pipenv

Чтобы понять преимущества Pipenv, важно ознакомиться с текущими методами упаковки и управления зависимостями в Python.

Начнем с типичной ситуации со сторонними пакетами. Затем мы проложим путь к развертыванию полного приложения Python.

Управление зависимостями сrequirements.txt

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

Итак, вы решили включить зависимостьflask в файлrequirements.txt:

flask

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

В приведенном выше файлеrequirements.txt не указано, какую версиюflask использовать. В этом случаеpip install -r requirements.txt по умолчанию установит последнюю версию. Это нормально, если только в последней версии нет изменений интерфейса или поведения, которые нарушают работу нашего приложения.

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

Теперь предположим, что вы развертываете свое приложение в производственной среде и выполняетеpip install -r requirements.txt. Pip получает последнюю, несовместимую с предыдущими версиями версиюflask, и вот так ваше приложение ломается ... в производстве.

“But hey, it worked on my machine!” - Я сам был там, и это не очень хорошее чувство.

На этом этапе вы знаете, что версияflask, которую вы использовали во время разработки, работала нормально. Итак, чтобы исправить ситуацию, вы стараетесь быть более конкретными в своихrequirements.txt. Вы добавляетеversion specifier к зависимостиflask. Это также называетсяpinning зависимостью:

flask==0.12.1

Прикрепление зависимостиflask к конкретной версии гарантирует, чтоpip install -r requirements.txt устанавливает точную версиюflask, которую вы использовали во время разработки. Но так ли это на самом деле?

Имейте в виду, что самflask также имеет зависимости (которыеpip устанавливает автоматически). Однако самflask не указывает точные версии для своих зависимостей. Например, он разрешает любую версиюWerkzeug>=0.14.

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

Когда вы на этот раз выполнитеpip install -r requirements.txt в производственной среде, вы получитеflask==0.12.1, так как вы закрепили это требование. Однако, к сожалению, вы получите последнюю версиюWerkzeug с ошибками. Опять же продукт перерыв в производстве.

Настоящая проблема здесь в том, чтоthe build isn’t deterministic. Я имею в виду, что при одном и том же вводе (файлrequirements.txt) pip не всегда создает одинаковую среду. В настоящее время вы не можете легко воспроизвести ту среду, которая у вас есть, на вашей машине для разработки в производстве.

Типичное решение этой проблемы - использоватьpip freeze. Эта команда позволяет вам получить точные версии для всех сторонних библиотек, установленных в данный момент, включая пипс зависимостей, установленный автоматически. Таким образом, вы можете заморозить все в процессе разработки, чтобы обеспечить одинаковую среду на производстве.

Выполнениеpip freeze приводит к закреплению зависимостей, которые вы можете добавить кrequirements.txt:

click==6.7
Flask==0.12.1
itsdangerous==0.24
Jinja2==2.10
MarkupSafe==1.0
Werkzeug==0.14.1

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

Теперь, когда вы указали точные версии каждого стороннего пакета, вы несете ответственность за поддержание этих версий в актуальном состоянии, даже если они являются подчиненными зависимостямиflask. Что, если вWerkzeug==0.14.1 обнаружена дыра в безопасности, которую разработчики пакета немедленно исправили вWerkzeug==0.14.2? Вам действительно необходимо выполнить обновление доWerkzeug==0.14.2, чтобы избежать каких-либо проблем с безопасностью, связанных с более ранней, не исправленной версиейWerkzeug.

Во-первых, вы должны знать, что есть проблема с версией, которая у вас есть. Затем вам нужно получить новую версию в вашей производственной среде, прежде чем кто-то воспользуется дырой в безопасности. Итак, вам нужно вручную изменитьrequirements.txt, чтобы указать новую версиюWerkzeug==0.14.2. Как вы можете видеть в этой ситуации, ответственность за своевременное обновление необходимых обновлений ложится на вас.

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

Настоящий вопрос:“How do you allow for deterministic builds for your Python project without gaining the responsibility of updating versions of sub-dependencies?”

Оповещение о спойлере: простой ответ - использование Pipenv.

Разработка проектов с разными зависимостями

Давайте немного переключимся, чтобы поговорить о другой распространенной проблеме, которая возникает, когда вы работаете над несколькими проектами. Представьте, чтоProjectA нуженdjango==1.9, аProjectB нуженdjango==1.10.

По умолчанию Python пытается сохранить все ваши сторонние пакеты в общесистемном расположении. Это означает, что каждый раз, когда вы хотите переключаться междуProjectA иProjectB, вы должны убедиться, что установлена ​​правильная версияdjango. Это делает переключение между проектами болезненным, потому что вам нужно удалить и переустановить пакеты, чтобы удовлетворить требования для каждого проекта.

Стандартное решение - использоватьvirtual environment, у которого есть собственный исполняемый файл Python и стороннее хранилище пакетов. Таким образом,ProjectA иProjectB должным образом разделены. Теперь вы можете легко переключаться между проектами, поскольку они не используют одно и то же место хранения пакетов. PackageA может иметь любую версиюdjango, которая ему нужна в его собственной среде, аPackageB может иметь то, что ему нужно, полностью отдельно. Очень распространенный инструмент для этого -virtualenv (илиvenv в Python 3).

В Pipenv встроено управление виртуальной средой, поэтому у вас есть единый инструмент для управления пакетами.

Разрешение зависимостей

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

package_a
package_b

Допустим,package_a имеет подчиненную зависимостьpackage_c, аpackage_a требует определенной версии этого пакета:package_c>=1.0. В свою очередь,package_b имеет такую ​​же подзависимость, но требуетpackage_c<=2.0.

В идеале, когда вы пытаетесь установитьpackage_a иpackage_b, инструмент установки будет смотреть на требования дляpackage_c (это>=1.0 и<=2.0) и выбирать версия, отвечающая этим требованиям. Вы надеетесь, что инструмент разрешит зависимости, чтобы ваша программа работала в конце. Это то, что я имею в виду под «разрешением зависимости».

К сожалению, сам pip в настоящий момент не имеет реального разрешения зависимостей, но естьopen issue для его поддержки.

Пип бы справился с описанным выше сценарием следующим образом:

  1. Он устанавливаетpackage_a и ищет версиюpackage_c, которая удовлетворяет первому требованию (package_c>=1.0).

  2. Затем Pip устанавливает последнюю версиюpackage_c для выполнения этого требования. Допустим, последняя версияpackage_c - 3.1.

Это где проблема (потенциально) начинается.

Если версияpackage_c, выбранная pip, не соответствует будущим требованиям (например,package_b требуетpackage_c<=2.0), установка завершится ошибкой.

«Решение» этой проблемы - указать диапазон, необходимый для подзависимости (package_c) в файлеrequirements.txt. Таким образом, pip может разрешить этот конфликт и установить пакет, соответствующий следующим требованиям:

package_c>=1.0,<=2.0
package_a
package_b

Однако, как и раньше, вы сейчас занимаетесь непосредственно подчиненными зависимостями (package_c). Проблема в том, что еслиpackage_a изменяет свои требования без вашего ведома, указанные вами требования (package_c>=1.0,<=2.0) могут больше не быть приемлемыми, и установка может завершиться неудачно… снова. Реальная проблема заключается в том, что вы снова несете ответственность за то, чтобы быть в курсе требований зависимостей.

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

Pipenv Введение

Теперь, когда мы решили проблемы, давайте посмотрим, как Pipenv решает их.

Во-первых, давайте установим его:

$ pip install pipenv

Как только вы это сделаете, вы можете забыть оpip, поскольку Pipenv, по сути, действует как замена. Он также вводит два новых файла:Pipfile (который предназначен для заменыrequirements.txt) иPipfile.lock (который позволяет выполнять детерминированные сборки).

Pipenv используетpip иvirtualenv под капотом, но упрощает их использование с помощью единого интерфейса командной строки.

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

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

$ pipenv shell

Это создаст виртуальную среду, если она еще не существует. Pipenv создает все ваши виртуальные среды в расположении по умолчанию. Если вы хотите изменить поведение Pipenv по умолчанию, есть несколькоenvironmental variables for configuration.

Вы можете принудительно создать среду Python 2 или 3 с аргументами--two и--three соответственно. В противном случае Pipenv будет использовать все найденные по умолчаниюvirtualenv.

Примечание: если вам требуется более конкретная версия Python, вы можете указать аргумент--python с нужной вам версией. Например:--python 3.6

Теперь вы можете установить необходимый сторонний пакетflask. О, но вы знаете, что вам нужна версия0.12.1, а не последняя версия, так что будьте конкретны:

$ pipenv install flask==0.12.1

Вы должны увидеть что-то вроде следующего в вашем терминале:

Adding flask==0.12.1 to Pipfile's [packages]...
Pipfile.lock not found, creating...

Вы заметите, что создаются два файла:Pipfile иPipfile.lock. Мы рассмотрим их подробнее через секунду. Давайте установим еще один сторонний пакет,numpy, для некоторой обработки чисел. Вам не нужна конкретная версия, поэтому не указывайте ее:

$ pipenv install numpy

Если вы хотите установить что-то непосредственно из системы контроля версий (VCS), вы можете! Вы указываете местоположения аналогично тому, как вы это делали бы сpip. Например, чтобы установить библиотекуrequests из системы контроля версий, сделайте следующее:

$ pipenv install -e git+https://github.com/requests/requests.git#egg=requests

Обратите внимание на аргумент-e выше, чтобы сделать установку редактируемой. В настоящее времяthis is required для Pipenv выполняет разрешение подчиненных зависимостей.

Допустим, у вас также есть несколько модульных тестов для этого замечательного приложения, и вы хотите использоватьpytest для их запуска. Вам не нуженpytest в производстве, поэтому вы можете указать, что эта зависимость предназначена только для разработки с аргументом--dev:

$ pipenv install pytest --dev

Предоставление аргумента--dev поместит зависимость в специальное место[dev-packages] вPipfile. Эти пакеты разработки будут установлены, только если вы укажете аргумент--dev сpipenv install.

Различные разделы отделяют зависимости, необходимые только для разработки, от зависимостей, необходимых для фактической работы базового кода. Обычно это достигается с помощью дополнительных файлов требований, таких какdev-requirements.txt илиtest-requirements.txt. Теперь все объединено в одинPipfile в разных разделах.

Итак, давайте представим, что у вас все работает в локальной среде разработки и вы готовы приступить к работе. Для этого вам нужно заблокировать свою среду, чтобы убедиться, что у вас есть такая же в рабочей среде:

$ pipenv lock

Это создаст / обновит вашPipfile.lock, который вам никогда не понадобится (и не предполагается) редактировать вручную. Вы всегда должны использовать сгенерированный файл.

Теперь, когда вы получите свой код иPipfile.lock в производственной среде, вам следует установить последнюю записанную успешную среду:

$ pipenv install --ignore-pipfile

Это говорит Pipenv игнорироватьPipfile при установке и использовать то, что находится вPipfile.lock. Учитывая этотPipfile.lock, Pipenv создаст точно такую ​​же среду, которая была у вас при запускеpipenv lock, подзависимостей и всего остального.

Файл блокировки позволяет выполнять детерминированные сборки, делая снимки всех версий пакетов в среде (аналогично результатуpip freeze).

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

$ pipenv install --dev

Это устанавливает все зависимости, необходимые для разработки, включая как обычные зависимости, так и те, которые вы указали с помощью аргумента--dev в течениеinstall.

Когда точная версия не указана в Pipfile, командаinstall дает возможность зависимостям (и вложенным зависимостям) обновить свои версии.

Это важное замечание, поскольку оно решает некоторые из предыдущих проблем, которые мы обсуждали. Для демонстрации, скажем, доступна новая версия одной из ваших зависимостей. Поскольку вам не нужна конкретная версия этой зависимости, вы не указываете точную версию вPipfile. Когда выpipenv install, новая версия зависимости будет установлена ​​в вашей среде разработки.

Теперь вы вносите свои изменения в код и запускаете несколько тестов, чтобы убедиться, что все по-прежнему работает должным образом. (У вас есть модульные тесты, верно?) Теперь, как и раньше, вы блокируете свою среду с помощьюpipenv lock, и обновленныйPipfile.lock будет сгенерирован с новой версией зависимости. Как и раньше, вы можете реплицировать эту новую среду в рабочей среде с помощью файла блокировки.

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

Подход к разрешению зависимостей Пипенва

Pipenv попытается установить подчиненные зависимости, которые удовлетворяют всем требованиям ваших основных зависимостей. Однако, если есть конфликтующие зависимости (package_a требуетpackage_c>=1.0, аpackage_b требуетpackage_c<1.0), Pipenv не сможет создать файл блокировки и выдаст ошибку типа следующее:

Warning: Your dependencies could not be resolved. You likely have a mismatch in your sub-dependencies.
  You can use $ pipenv install --skip-lock to bypass this mechanism, then run $ pipenv graph to inspect the situation.
Could not find a version that matches package_c>=1.0,package_c<1.0

Как говорится в предупреждении, вы также можете отобразить граф зависимостей, чтобы понять ваши зависимости верхнего уровня и их подчиненные зависимости:

$ pipenv graph

Эта команда выведет древовидную структуру, показывающую ваши зависимости. Вот пример:

Flask==0.12.1
  - click [required: >=2.0, installed: 6.7]
  - itsdangerous [required: >=0.21, installed: 0.24]
  - Jinja2 [required: >=2.4, installed: 2.10]
    - MarkupSafe [required: >=0.23, installed: 1.0]
  - Werkzeug [required: >=0.7, installed: 0.14.1]
numpy==1.14.1
pytest==3.4.1
  - attrs [required: >=17.2.0, installed: 17.4.0]
  - funcsigs [required: Any, installed: 1.0.2]
  - pluggy [required: <0.7,>=0.5, installed: 0.6.0]
  - py [required: >=1.5.0, installed: 1.5.2]
  - setuptools [required: Any, installed: 38.5.1]
  - six [required: >=1.10.0, installed: 1.11.0]
requests==2.18.4
  - certifi [required: >=2017.4.17, installed: 2018.1.18]
  - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4]
  - idna [required: >=2.5,<2.7, installed: 2.6]
  - urllib3 [required: <1.23,>=1.21.1, installed: 1.22]

Из выводаpipenv graph вы можете увидеть зависимости верхнего уровня, которые мы установили ранее (Flask,numpy,pytest иrequests), а также ниже вы можете увидеть пакеты, от которых они зависят.

Кроме того, вы можете перевернуть дерево, чтобы показать подчиненные зависимости с родителем, которому это необходимо:

$ pipenv graph --reverse

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

Пипфайл

Pipfile намеревается заменитьrequirements.txt. Pipenv в настоящее время является эталонной реализацией для использованияPipfile. Весьма вероятно, чтоpip itself will be able to handle these files. Также стоит отметить, чтоPipenv is even the official package management tool recommended by Python itself.

Синтаксис дляPipfile -TOML, и файл разделен на разделы. [dev-packages] для пакетов, предназначенных только для разработки,[packages] для минимально необходимых пакетов и[requires] для других требований, таких как конкретная версия Python. Смотрите пример файла ниже:

[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"

[dev-packages]
pytest = "*"

[packages]
flask = "==0.12.1"
numpy = "*"
requests = {git = "https://github.com/requests/requests.git", editable = true}

[requires]
python_version = "3.6"

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

Pipfile.lock

Этот файл включает детерминированные сборки, указывая точные требования для воспроизведения среды. Он содержит точные версии пакетов и хэшей для поддержки более безопасной проверки, в том числеpip itself now supports. Пример файла может выглядеть следующим образом. Обратите внимание, что синтаксис этого файла - JSON, и что я исключил части файла с...:

{
    "_meta": {
        ...
    },
    "default": {
        "flask": {
            "hashes": [
                "sha256:6c3130c8927109a08225993e4e503de4ac4f2678678ae211b33b519c622a7242",
                "sha256:9dce4b6bfbb5b062181d3f7da8f727ff70c1156cbb4024351eafd426deb5fb88"
            ],
            "version": "==0.12.1"
        },
        "requests": {
            "editable": true,
            "git": "https://github.com/requests/requests.git",
            "ref": "4ea09e49f7d518d365e7c6f7ff6ed9ca70d6ec2e"
        },
        "werkzeug": {
            "hashes": [
                "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b",
                "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c"
            ],
            "version": "==0.14.1"
        }
        ...
    },
    "develop": {
        "pytest": {
            "hashes": [
                "sha256:8970e25181e15ab14ae895599a0a0e0ade7d1f1c4c8ca1072ce16f25526a184d",
                "sha256:9ddcb879c8cc859d2540204b5399011f842e5e8823674bf429f70ada281b3cc6"
            ],
            "version": "==3.4.1"
        },
        ...
    }
}

Обратите внимание на точную версию, указанную для каждой зависимости. Даже подчиненные зависимости, такие какwerkzeug, которых нет в нашемPipfile, появляются в этомPipfile.lock. Хэши используются для того, чтобы вы получали тот же пакет, что и в разработке.

Стоит еще раз отметить, что вы никогда не должны изменять этот файл вручную. Он предназначен для создания с помощьюpipenv lock.

Дополнительные возможности Pipenv

Откройте сторонний пакет в редакторе по умолчанию с помощью следующей команды:

$ pipenv open flask

Это откроет пакетflask в редакторе по умолчанию, или вы можете указать программу с переменной окруженияEDITOR. Например, я используюSublime Text, поэтому я просто устанавливаюEDITOR=subl. Это делает очень простым копание во внутренностях пакета, который вы используете.


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

$ pipenv run 

Проверьте наличие уязвимостей безопасности (и требованийPEP 508) в вашей среде:

$ pipenv check

Теперь, допустим, вам больше не нужен пакет. Вы можете удалить его:

$ pipenv uninstall numpy

Кроме того, допустим, вы хотите полностью стереть все установленные пакеты из вашей виртуальной среды:

$ pipenv uninstall --all

Вы можете заменить--all на--all-dev, чтобы просто удалить пакеты разработчика.


Pipenv поддерживает автоматическую загрузку переменных окружения, когда файл.env существует в каталоге верхнего уровня. Таким образом, когда выpipenv shell открываете виртуальную среду, она загружает ваши переменные среды из файла. Файл.env содержит только пары ключ-значение:

SOME_ENV_CONFIG=some_value
SOME_OTHER_ENV_CONFIG=some_other_value

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

$ pipenv --venv

Как узнать, где находится ваш проект дома:

$ pipenv --where

Распределение пакетов

Вы можете спросить, как все это работает, если вы собираетесь распространять свой код в виде пакета.

Да, мне нужно распространять свой код в виде пакета

Как Pipenv работает с файламиsetup.py?

В этом вопросе много нюансов. Во-первых, если вы используетеsetuptools в качестве системы сборки / распространения, необходим файлsetup.py. Некоторое время это было стандартом де-факто, ноrecent changes сделали использованиеsetuptools необязательным.

Это означает, что такие проекты, какflit, могут использовать новыйpyproject.toml для указания другой системы сборки, для которой не требуетсяsetup.py.

При этом в ближайшем будущемsetuptools и сопровождающий ихsetup.py по-прежнему будут выбором по умолчанию для многих людей.

Вот рекомендуемый рабочий процесс, когда вы используетеsetup.py как способ распространения своего пакета:

  • setup.py

  • Ключевое словоinstall_requires должно включать все, что содержится в пакете“minimally needs to run correctly.”

  • Pipfile

  • Представляет конкретные требования для вашего пакета

  • Получите минимально необходимые зависимости изsetup.py, установив свой пакет с помощью Pipenv:

    • Используйтеpipenv install '-e .'

    • Это приведет к тому, что в вашемPipfile появится строка, которая выглядит примерно как"e1839a8" = {path = ".", editable = true}.

  • Pipfile.lock

  • Детали для воспроизводимой среды, созданной изpipenv lock

Чтобы уточнить, укажите минимальные требования вsetup.py, а не непосредственно вpipenv install. Затем используйте командуpipenv install '-e .', чтобы установить ваш пакет как редактируемый. Благодаря этому в вашу среду будут включены все требования отsetup.py. Затем вы можете использоватьpipenv lock для получения воспроизводимой среды.

Мне не нужно распространять свой код в виде пакета

Большой! Если вы разрабатываете приложение, которое не предназначено для распространения или установки (персональный веб-сайт, настольное приложение, игра или подобное), вам действительно не нуженsetup.py.

В этой ситуации вы можете использовать комбоPipfile /Pipfile.lock для управления своими зависимостями с помощью описанного ранее потока для развертывания воспроизводимой среды в производственной среде.

У меня уже естьrequirements.txt. Как мне преобразовать вPipfile?

Если вы запуститеpipenv install, он должен автоматически определитьrequirements.txt и преобразовать его вPipfile, получив что-то вроде следующего:

requirements.txt found, instead of Pipfile! Converting…
Warning: Your Pipfile now contains pinned versions, if your requirements.txt did.
We recommend updating your Pipfile to specify the "*" version, instead.

Обратите внимание на приведенное выше предупреждение.

Если вы закрепили точные версии в файлеrequirements.txt, вы, вероятно, захотите изменить свойPipfile, чтобы указать только точные версии, которые вам действительно нужны. Это позволит вам получить реальные выгоды от перехода. Например, предположим, что у вас есть следующее, но вам действительно не нужна точная версияnumpy:

[packages]
numpy = "==1.14.1"

Если у вас нет конкретных требований к версии для ваших зависимостей, вы можете использовать подстановочный знак*, чтобы сообщить Pipenv, что можно установить любую версию:

[packages]
numpy = "*"

Если вы нервничаете из-за того, что разрешаете любую версию с*, обычно лучше указать версию, которая больше или равна той, что у вас уже есть, чтобы вы по-прежнему могли пользоваться преимуществами новых версий:

[packages]
numpy = ">=1.14.1"

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

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

Например, еслиnumpy==1.15 устанавливается после запускаpipenv install и он нарушает ваш код, что вы, надеюсь, заметите во время разработки или во время тестов, у вас есть несколько вариантов:

  1. Обновите ваш код для работы с новой версией зависимости.

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

    [packages]
    numpy = ">=1.15"
  2. Ограничьте версию зависимости вPipfile< версией, которая только что нарушила ваш код:

    [packages]
    numpy = ">=1.14.1,<1.15"

Вариант 1 предпочтителен, так как он гарантирует, что ваш код использует самые современные зависимости. Однако вариант 2 занимает меньше времени и не требует изменений кода, только ограничения на зависимости.


Вы также можете установить из файлов требований с тем же аргументом-r, который принимаетpip:

$ pipenv install -r requirements.txt

Если у вас естьdev-requirements.txt или что-то подобное, вы также можете добавить их кPipfile. Просто добавьте аргумент--dev, чтобы он попал в правильный раздел:

$ pipenv install -r dev-requirements.txt --dev

Кроме того, вы можете пойти другим путем и сгенерировать файлы требований изPipfile:

$ pipenv lock -r > requirements.txt
$ pipenv lock -r -d > dev-requirements.txt

Что дальше?

Мне кажется, что естественным развитием экосистемы Python будет система сборки, которая используетPipfile для установки минимально необходимых зависимостей при извлечении и сборке пакета из индекса пакета (например, PyPI). Еще раз важно отметить, чтоPipfile design specification все еще находится в разработке, а Pipenv - всего лишь эталонная реализация.

При этом я мог бы увидеть будущее, в котором разделinstall_requires вsetup.py не существует, а вместо этого используется ссылка наPipfile для минимальных требований. Илиsetup.py полностью исчез, и вы получаете метаданные и другую информацию другим способом, по-прежнему используяPipfile для получения необходимых зависимостей.

Стоит ли проверять Pipenv?

Определенно. Даже если это просто способ объединить инструменты, которые вы уже используете (pip &virtualenv) в одном интерфейсе. Тем не менее, это гораздо больше, чем это. ДобавляяPipfile, вы указываете только те зависимости, которые вам действительно нужны.

У вас больше нет головной боли, когда вы сами управляете версиями всего лишь для того, чтобы обеспечить возможность репликации среды разработки. ИспользуяPipfile.lock, вы можете спокойно развиваться, зная, что вы можете точно воспроизвести свою среду в любом месте.

В дополнение ко всему этому, весьма вероятно, что форматPipfile будет принят и поддержан официальными инструментами Python, такими какpip, так что было бы полезно быть впереди всех. Да, и убедитесь, что вы также обновляете весь свой код до Python 3:2020 is coming up fast.

Ссылки, дальнейшее чтение, интересные дискуссии и пр.

Free Bonus:Click here to get access to a free 5-day class, который показывает, как избежать распространенных проблем управления зависимостями с такими инструментами, как Pip, PyPI, Virtualenv и файлами требований.