Pipenv: Цель: обеспечить непротиворечивость файла блокировки после всех команд установки.

Созданный на 31 дек. 2017  ·  50Комментарии  ·  Источник: pypa/pipenv

Как указано в https://github.com/pypa/pipenv/issues/1137 , pipenv настоящее время не проверяет конфликты требований между [packages] и [dev-packages] , что может вызывать проблемы при попытке сгенерировать плоский requirements.txt который охватывает оба, а также вызывает общие странности при конфликте зависимостей.

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

Эта проблема не касается отдельного запроса функции. Вместо этого он ставит цель помочь обеспечить согласованность между файлом блокировки и локальной средой, структурируя команды установки, чтобы сначала изменить файл блокировки, а затем использовать обновленный файл блокировки для управления фактическим шагом установки. (У нас нет какого-либо целевого ETA относительно того, сколько времени займет эта работа - его запись просто предназначена для того, чтобы гарантировать, что мы все движемся в одном направлении, и всем комфортно с этим направлением)

Ключевым аспектом этого будет уточнение разделения ответственности между pipenv install , pipenv uninstall , pipenv lock и pipenv update (и, возможно, добавление одного или нескольких новые подкоманды, если это необходимо).

Предлагаемые подэтапы:

  • [x] добавить подкоманду pipenv sync которая гарантирует, что текущая среда соответствует файлу блокировки (аналогично pip-sync в pip-tools ). (Реализовано @kennethreitz для 10.0.0, при этом pipenv sync гарантирует, что версии заблокированных пакетов соответствуют файлу блокировки, а pipenv clean удаляет пакеты, которых нет в файле блокировки. Мне нравится это относительное изменение на pip-sync , поскольку это означает, что включение неявной синхронизации в другую команду не приведет к неожиданному удалению чего-либо из виртуальной среды)
  • [x] Сохраните текущее поведение для pipenv install без аргументов, но переключитесь на рекомендацию использования pipenv sync при настройке новой среды (таким образом, pipenv install используется в основном для замена установленных компонентов)
  • [x] обновите pipenv lock чтобы всегда гарантировать, что [packages] и [dev-packages] согласованы друг с другом (разрешение для # 1137)
  • [x] изменить pipenv update на эквивалент pipenv lock && pipenv sync (обновление pipenv вместо этого полностью удаляется - его старое поведение было фактически сопоставимо с тем, что сейчас является pipenv sync && pipenv clean )
  • [x] добавить новый параметр pipenv lock --keep-outdated который по-прежнему генерирует новый Pipfile.lock из Pipfile , но сводит к минимуму изменения, внесенные только в те, которые необходимы для удовлетворения любых изменений, внесенных в Pipfile (будь то добавление, удаление пакета или изменение ограничений версии)
  • [x] изменить pipenv install <packages> на «добавить или обновить записи в Pipfile», за которым следует pipenv lock && pipenv sync (реализовано в # 1486).
  • [x] Добавьте в pipenv install параметр --keep-outdated который он передает в операцию pipenv lock .
  • [x] добавить новую функцию pipenv install --selective-upgrade <packages> которая семантически эквивалентна «удалить эти записи пакета из Pipfile (если есть)», запустить pipenv lock --keep-outdated , затем запустить pipenv install --keep-outdated <packages> (это последний шаг, обеспечивающий поддержку https://github.com/pypa/pipenv/issues/966). Если указано только имя пакета, то используется существующее ограничение версии в Pipfile , в противном случае данное ограничение версии перезаписывает существующее. Влияние этого на текущую среду должно быть таким же, как pip install --upgrade --upgrade-strategy=only-if-needed <packages> в пункте 9+ (за исключением того, что Pipfile.lock также будет обновлено).

Если кто-то хочет воспользоваться одним из этих подшагов, оставьте комментарий ниже, чтобы сказать, что вы работаете над ним (чтобы попытаться свести к минимуму дублирование усилий), а затем отправьте PR-ссылку на эту проблему. (Шаги, перечисленные ранее, необходимо будет выполнить, прежде чем последующие шаги станут практическими)

Открытые вопросы:

  • Никто

Решенные вопросы (по крайней мере, на ближайшее время):

  • pipenv lock будет по-прежнему обновлять все по умолчанию, а pipenv lock --keep-outdated запрашивает минимальное обновление, которое только корректирует файл блокировки с учетом изменений Pipfile (добавления, удаления и изменения в ограничениях версии)
  • pipenv lock --skip-lock будет продолжать работать так же, как и сегодня (даже если это означает, что файл блокировки и локальная среда могут не синхронизироваться: используйте pipenv sync && pipenv clean для их повторной синхронизации)
  • pipenv install и pipenv install <package> прежнему будут означать полный pipenv lock по умолчанию, при этом pipenv install --keep-outdated требуется для запроса только минимальных изменений, необходимых для удовлетворения запроса на установку
  • pipenv install <package> продолжит сохранять существующее ограничение версии в Pipfile если в командной строке ничего не указано, даже для новой опции --selective-upgrade
  • pipenv uninstall <package> просто удалит указанный пакет [ы] и, следовательно, может оставить больше не нужные зависимости в локальной среде. Запуск pipenv lock && pipenv sync && pipenv clean очистит их.

Примечание: исходное предложение здесь было просто обеспечить синхронизацию [dev-packages] и [packages] при создании файла блокировки, и первые несколько сообщений отражают это. Вместо этого текущее предложение охватывает предложение по симметричному обновлению на основе файла блокировки, впервые упомянутое в https://github.com/pypa/pipenv/issues/1255#issuecomment -354585775

Future Discussion Type

Самый полезный комментарий

--selective-upgrade готово.

Все 50 Комментарий

Отмечая здесь потенциальную проблему реализации: я не уверен, что pip-tools настоящее время поддерживает файлы ограничений, и в этом случае нам нужно сначала добавить эту поддержку, чтобы получить все преимущества этого подхода.

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

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

В основном вы можете сделать это с помощью предложения LocalRequirementsRepository за @vphilippon , чтобы не обновлять несвязанные зависимости в https://github.com/pypa/pipenv/issues/966#issuecomment -339707418. Это похоже на https://github.com/taion/pipf/blob/1feee35a2e4480bc7e5b53bfab17587d37bdf9dd/pipf/pipfile.py#L175 -L185.

См. Также https://github.com/pypa/pipfile/issues/100. По-прежнему основной проблемой является то, что Pipfile.lock может даже представлять несколько несовместимых наборов зависимостей для разных групп.

@taion Мы не собираемся переключать Pipfile.lock на плоское представление, поскольку мы хотим поддерживать инструменты, повторно блокирующие зависимости развертывания, даже не глядя на зависимости разработки. Да, это означает, что раздел [dev-packages] может устареть, но цель этой проблемы: убедиться, что, когда раздел [dev-packages] действительно обновится, он будет повторно синхронизирован с раздел пакетов развертывания.

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

На практике с точки зрения пользователя это просто частный случай https://github.com/pypa/pipenv/issues/966 и других связанных (закрытых) проблем.

Как и в худшем случае, вы просто кешируете разрешенные транзитивные зависимости в файле блокировки. Пряжа и npm уже делают это. Это позволит вам обновлять все ваши продукты, не нажимая PyPI для разработчиков.

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

Я также добавлю, что npm на самом деле поддерживает обновление только производственных зависимостей, а не разрабатываемых, и на самом деле он использует плоский файл блокировки (с кешированными разрешениями).

Достаточно интересно, что Yarn не использует подкоманду для массового обновления зависимостей (хотя интерактивная версия разделяет зависимости prod и dev), и не похоже, что кто-то жаловался на это, но это, вероятно, можно списать на npm -похоже на использование диапазонов каретки для зависимостей по умолчанию, плюс люди, как правило, достаточно хорошо следят за SemVer, чтобы изредка вызывать у пользователей проблемы из-за увеличения количества разработчиков. Экосистема Python, не так уж и много.

@taion Явное pipenv lock уже полностью разрешает как [packages] и [dev-packages] , поэтому нам не нужно беспокоиться о дрейфе конфигурации в этом случае (и это тот случай, когда я думаю наиболее желательно обнаруживать конфликты зависимостей).

Если есть симметричное решение, которое также позволяет как pipenv install package и pipenv install --dev package обнаруживать (и разрешать) несоответствия, то я согласен, что это будет хороший способ. Однако я бы тоже согласился с асимметричным решением, если бы его было проще реализовать (отсюда и формулировка этого предложения).

Что касается симметричного подхода, я думаю, что одним из способов его создания и реализации было бы следовать подходу, описанному @vphilippon в https://github.com/pypa/pipenv/issues/966#issuecomment -339791934, но структурировать его следующим образом :

  • добавить параметр pipenv lock --keep-outdated чтобы запросить минимальное обновление файла блокировки, а не полное обновление по умолчанию
  • измените pipenv install package на "редактировать файл Pipfile -> pipenv lock --keep-outdated -> pipenv install "

(Примечание: по соображениям управления безопасностью я действительно хочу сохранить поведение по умолчанию pipenv lock как обновление всего - однако я думаю, что такая функция, как --keep-outdated имеет место, когда другие механизмы используются для обеспечения своевременного реагирования на обнаруженные проблемы безопасности в зависимостях)

Поведение, которое вы описываете для pipenv install в основном совпадает с тем, к чему стремится # 966, но это не совсем то же самое. Представьте, что у вас есть X = "*" . Выполнение pipenv install X вероятно, по-прежнему должно обновить X в файле блокировки, даже если нет изменений в Pipfile . Pipenv необходимо отслеживать, что _ на самом деле_ обновляется.

Другими словами, вы не можете полностью отделить «установку» от «блокировки». См., Например, https://github.com/taion/pipf/blob/1feee35a2e4480bc7e5b53bfab17587d37bdf9dd/pipf/pipfile.py#L150 -L155 - при регенерации файла блокировки я явно передаю устанавливаемые пакеты, чтобы отменить старые ограничения для этих .

Жалоба в любом случае не в том, что что-то вроде явного pipenv lock обновляет все зависимости до последних доступных; это то, что pipenv install Y касается версии для несвязанного X . Другими словами, людям действительно не нужно явно запускать pipenv lock --keep-outdated .

Обработка Yarn здесь - довольно хороший пример с точки зрения интерфейса командной строки. В Yarn есть yarn lockfile , который генерирует файл блокировки, ничего не меняя, и явно помечен как «[не] необходимый», и у него есть yarn upgrade который обновляет все. Если по какой-то причине вы вручную редактируете свои зависимости, следующим шагом будет просто запустить yarn install , который обновит ваш файл блокировки (минимально) и установит необходимые пакеты.

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

  1. Установите все зависимости
  2. Добавить или обновить одну или несколько конкретных зависимостей
  3. Обновите все зависимости

Пункты (1) и (2) всегда должны вносить минимальные изменения в мой файл блокировки (или генерировать его, если необходимо), а (3) по существу игнорирует существующий файл блокировки. Но для создания файла блокировки достаточно (1) (поскольку он будет запускаться из среды разработки, в которой все равно все установлено).

PS Yarn отделяет yarn add (добавить зависимость) от yarn install (установить все зависимости). Сначала это немного сбивало с толку и раздражало, но чем больше я им пользовался, тем больше мне нравилось это различие. Наличие одной команды install которая одновременно добавляет определенные зависимости _ и_ устанавливает все зависимости проекта, довольно странно, если подумать. Эти два действия - не одно и то же.

Первые несколько абзацев в https://lwn.net/Articles/711906/ довольно хорошо описывают мой образ мышления: «движущаяся цель» должна быть моделью безопасности по умолчанию для всех проектов, и отказ от этого Подход «укрепленного бункера» должен быть осознанным дизайнерским решением, принимаемым только после рассмотрения компромиссов.

Отсюда и выбор имени параметра: --keep-outdated не просто вдохновлен pip list --outdated , он также намеренно выбран, чтобы выглядеть сомнительно в командной строке (поскольку сохранение устаревших зависимостей по своей природе опасно из-за перспектива безопасности).

В конкретном случае pipenv install X он не должен неявно выполнять обновление, потому что pip install X неявно не выполняет обновления.

pipenv в настоящее время несовместим с этим последним пунктом, поскольку он выполняет следующие действия:

  • вызывает pip install package (без неявного обновления)
  • вызывает pipenv lock (неявные обновления)

Таким образом, идея обеспечения согласованности путем постоянного использования файла блокировки для управления установкой (если не используется --skip-lock ) и предложения pipenv lock --keep-outdated в соответствии со стратегией обновления only-if-needed pip.

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

И, конечно, pipenv install -U <package> для обновления одного пакета лучше было бы параллельно с Pip.

Однако я говорю, что в обычном рабочем процессе у пользователей нет причин запускать pipenv lock , с --keep-outdated или без него или без него. Наборы команд, которые пользователь может запускать для различных сценариев:

  • Начальная загрузка нового пакета: pipenv init
  • Создание нового клона проекта: pipenv install
  • Добавление новой зависимости: pipenv install <package> (и еще раз обратите внимание, что Yarn называет это add , что является хорошей идеей)
  • Повторно синхронизировать установленные зависимости после редактирования вручную Pipfile : pipenv install
  • Обновление всех зависимостей до последних совместимых версий: pipenv update

Все вышеперечисленные действия синхронизируют Pipfile.lock .

Или, другими словами, мне никогда не приходилось запускать npm shrinkwrap (с npm 5), и мне никогда не приходилось запускать yarn lockfile .

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

FWIW, я запускаю инструмент, который автоматически создает PR обновления зависимостей ( Dependabot ), в том числе для Pipfiles, и мне бы понравился вариант pipenv lock --keep-outdated . В настоящий момент мы редактируем Pipfiles, чтобы заблокировать все зависимости, кроме той, которую мы обновляем при создании PR.

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

Верно, и генерация PR - это то место, где, я думаю, будет полезно pipenv lock --keep-outdated : он предполагает, что шаг «pipenv install && run the tests» будет происходить удаленно на сервере CI, а не на машине, на которой был сгенерирован PR. Точно так же pipenv lock предназначен для случая, когда вы стремитесь сгенерировать PR пакетного обновления, которое вы собираетесь протестировать в CI, не беспокоясь о локальном применении изменения.

В этом ключе, если бы pipenv install <requirement> стало эквивалентом "update Pipfile + pipenv lock --keep-outdated + pipenv install ", тогда было бы разумно, чтобы pipenv update стало эквивалентным в pipenv lock && pipenv install .

В то время как yarn проводит различие между yarn install и yarn add , если бы мы когда-либо добавили такое различие к pipenv , я был бы более склонен брать взаймы из терминологии pip-tools и добавьте команду pipenv sync чтобы сказать: «Сделайте текущую среду соответствующей файлу блокировки». Однако это выходит за рамки данного предложения: при этом следует уделять особое внимание устранению возможности возникновения расхождений между зависимостями развертывания и зависимостями разработки.

@greysteil

Эквивалент для Greenkeeper / & c. вариант использования с npm заключается в следующем, верно?

$ npm install --package-lock-only <package><strong i="8">@latest</strong>

Фактически, npm5 даже предоставляет способ _просто_ создать package-lock.json вне npm install ?

@ncoghlan

Сервисы, подобные Greenkeeper, очень круты и их стоит использовать, но было бы странно считать, что это основной вариант использования (и, как отмечалось выше, даже тот случай, когда «обновите одну зависимость и файл блокировки, но не устанавливайте что-то» допускает более чистое выражение).

Ой, я нажал "Enter" слишком рано. Вне рабочих процессов в стиле Greenkeeper практически исчезающе редко _ просто_ увеличивать мои зависимости без их локальной синхронизации. Это имеет смысл только в том случае, если у вас почему-то не установлена ​​локальная копия deps. И снова PR-услуги - исключение, но только это.

Описание здесь - «Рабочий процесс разработки Python для людей », и поэтому стоит помнить, как выглядят реальные рабочие процессы разработки. И у нас есть довольно хорошее доказательство того, что явный запуск операции «сгенерировать файл блокировки» почти никогда не требуется, так что не стоит слишком много думать об этом.


Конкретная проблема здесь, кстати, заключается в том, что Pipenv по умолчанию использует диапазоны * . Если я сделаю pipenv install flask , я получу flask = "*" в моем Pipfile . Это означает, что если я хочу обновить установленную версию Flask чистым способом, то это будет изменение только для файла блокировки.

Обновление операция может в принципе выключатель А * требование к >= диапазона или что - то в Pipfile , но это создает странную асимметрию между «обновить» и «начальная установка». Возможно, лучшим решением здесь могло бы быть использование диапазонов >= для начальной установки в любом случае. По крайней мере, я не уверен, что вижу вескую причину для использования там диапазонов * .

@taion - да, согласен, не ожидая, что вы, ребята, будете слишком много думать о нас / других инструментах обновления зависимостей, хотя очень благодарен, если вы это сделаете! Я упомянул об этом только потому, что знаю, что использовал бы pipenv lock --keep-outdated вручную, если бы обновлял зависимости на моем предыдущем рабочем месте (у нас был один PR на политику обновления зависимостей).

Для справки: npm добавила параметр package-lock-only в последний выпуск ( журнал изменений ).

@greysteil Что делать, если у кого-то есть диапазон * в Pipfile ? Как в моем примере flask = "*" выше. Как есть, учитывая то, как Pipenv добавляет зависимости по умолчанию, вам нужно знать, какое требование нужно открепить при восстановлении файла блокировки, нет?

_Я не понимаю работу Pipenv даже близко к деталям, которые делают другие участники этой ветки, и не хочу выносить это вне темы. Если приведенное ниже полезно, отлично. Если нет, извините! _

Мы используем неприятный хакс:

  • Чтобы найти версию для обновления, в настоящее время мы просто получаем последнюю версию (мы должны использовать преобразователь в pip-tool , но пока не делаем этого. Оказывается, это не так уж и плохо, так как следующий шаг приведет к ошибке, если он неразрешим. )
  • Чтобы создать Pipfile.lock который обновляет только эту (верхнюю) зависимость, мы

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

    2. Разобрать существующий файл блокировки

    3. Обновите Pipfile, чтобы установить требование для каждой другой зависимости от того, что было разрешено в файле блокировки.

    4. Запустите pipenv lock чтобы сгенерировать новый файл блокировки

    5. Обновите хэш во вновь созданном файле блокировки, чтобы он был таким, каким он был бы, если бы мы не выполнили шаг 3 (ужасный взлом, который я бы очень хотел удалить)

Конечным результатом является то, что пользователь получает PR с неизмененным Pipfile (если требовалось * ), но его Pipfile.lock обновлены для использования последней версии этой зависимости.

Насколько я понимаю, pipenv lock --keep-outdated позволит мне вместо этого использовать следующий поток:

  1. Обновление требования о зависимости мы обновляем равные последнюю версию
  2. Запустите pipenv lock --keep-outdated чтобы сгенерировать новый файл блокировки
  3. Обновите хэш во вновь созданном файле блокировки, чтобы он был таким, каким он был бы, если бы мы обновили только Pipfile для поддержки последней версии.

Так что это было бы намного лучше. Идеально было бы запустить pipenv lock --keep-outdated <some_package_name> , но нищие не могут выбирать! : octocat:

Предположим, в моем Pipfile есть:

flask = "*"
numpy = "*"

flask транзитивно зависит от werkzeug . Предположим, есть обновления для flask и numpy , и я хочу обновить свою версию flask , но не обновлять свою версию numpy .

Если бы я не использовал Pipenv, я бы просто запустил:

$ pip install -U flask
$ pip freeze > requirements.txt

Если бы я использовал pip-tools, я бы запустил:

$ pip-compile -P flask
$ pip-sync # Or: pip install -r requirements.txt

Ну, просто выполнение некоторых гипотетических pipenv lock --keep-outdated ничего не даст. С другой стороны, полное восстановление файла блокировки также обновит NumPy.

Но если я не ошибаюсь, описанная выше стратегия обновит только версию flask в файле блокировки, но не версию werkzeug . Тогда это может быть недопустимый набор зависимостей, если новая версия flask также _требует_ новую версию werkzeug .

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

Проблема здесь, в частности, в зависимостях * . Npm справляется с этим, чтобы начать с чего-то вроде:

flask = ">=0.12.1"

А затем при запросе обновления увеличьте его до:

flask = ">=0.12.2"

В этом случае приведенная выше стратегия запуска чего-то вроде pipenv lock --keep-outdated будет правильной. Но если вы используете диапазон * , то я не вижу реального способа сделать это без специального инструмента, такого как pipenv install -U flask , который затем отбрасывает flask специально как предлагаемый штифт при восстановлении файла блокировки.

Извините, я не совсем понял шаг (iii) выше. Мы блокируем все зависимости верхнего уровня для версии в файле блокировки, но оставляем дочерние зависимости разблокированными.

@greysteil Я вижу - значит, это потенциально может обновить транзитивные зависимости других прямых зависимостей?

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

(Я бы предпочел, чтобы поведение было ближе к Ruby Bundler, где также могут быть обновлены только подзависимости обновляемой зависимости, но сильное вооружение pipenv для этого, похоже, не стоило хакерских действий.)

@taion По замыслу pipenv почти полностью сосредоточен на модели безопасности "движущейся цели", которую я описал в своем выступлении по LCA. Таким образом, две предполагаемые модели использования заключаются в следующем:

  • Интерактивные пакетные обновления:

    • Человек периодически выполняет какое-то действие (явное пакетное обновление, добавление новой зависимости, обновление явной зависимости)
    • В рамках этих операций файл блокировки и текущая среда обновляются до последней версии всего, что удовлетворяет выраженным ограничениям в Pipfile
    • Со временем либо выраженные ограничения обновляются (и выбранные зависимости отключаются), пока этот способ работы не станет безболезненным, либо разработчики переключатся на второй вариант ниже.
  • Автоматические выборочные обновления:

    • Автоматизированный процесс следит за появлением новых версий зависимостей и отправляет сообщение о проблеме + PR, когда они становятся доступными.
    • Люди в основном создают новые среды, явно добавляют зависимости и регулируют выраженные ограничения для существующих зависимостей.

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

Но эта основная философия дизайна «По умолчанию запускает последнюю версию всего, если явно не указано иное в Pipfile » не изменится - мы просто хотим добавить достаточную поддержку выборочного обновления, чтобы лучше справиться с ситуацией, когда большинство обновления файла блокировки отправляются службой управления обновлениями, а не людьми.

Приятно читать, что автоматизированные инструменты - это случай использования @ncoghlan, о котором вы думаете. 🎉

Если вам когда-нибудь понадобится обратная связь о том, что Dependabot / другие хотели бы / нуждаться, дайте мне знать. Python - не мой домашний язык, поэтому я еще не смог внести свой вклад в pip / pipenv, но я хотел бы помочь любым возможным способом.

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

@techalchemy Хорошо, я pipenv lock --keep-outdated + pipenv install --ignore-pipfile , вместо того, чтобы сначала запускать установку, как мы делаем сейчас) .

Это все равно оставит нам несколько открытых вопросов (например, как --skip-lock должен работать в этой модели), но этого должно быть достаточно, чтобы начать разбивать отдельные запросы функций (например, добавить --keep-outdated к pipenv lock за запрос стратегии обновления только в случае необходимости)

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

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

Выглядит отлично. Что касается открытых вопросов, я полностью согласен с предложенным поведением для pip install --selective-upgrade <package> (т. Е. Выполнить обновление, которое учитывает существующее ограничение версии, если не задано новое). Такое поведение часто требуется при обновлении одного пакета - я могу представить людей, выполняющих pip install --selective-upgrade django где у вас есть ограничение < 2.0 которое вы хотите соблюдать.

Стоит пояснить некоторые из приведенных выше текстов - предлагаемый pipenv install --selective-upgrade должен быть примерно идентичен стандартному pip install -U .

И, опять же, на практике люди много думали об этом при создании других менеджеров пакетов. Возможно, в вакууме рабочие процессы, которые вы описываете в https://github.com/pypa/pipenv/issues/1255#issuecomment -355435921, имеют смысл, но, например, цель здесь - создать «Рабочий процесс разработки Python для людей», или для экспериментов с новыми рабочими процессами разработки?

Pipenv - действительно крутой проект, который многое делает лучше, но я думаю, что здесь есть довольно фундаментальная путаница в целях. Блокировка менеджеров пакетов в наши дни в значительной степени стандартна, и здорово, что у Python есть благословенный менеджер, но я не думаю, что объединять «изучение нового теоретического рабочего процесса управления пакетами» и «создание рабочего процесса управления пакетами, который ведет себя так, как ожидают люди. "является положительным.

Снова обратите внимание, например, на http://bundler.io/v1.16/man/bundle-install.1.html#CONSERVATIVE -UPDATING и многие, многие другие.

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

Чтобы сделать эту лакмусовую бумажку более явной:

  1. Вы активно использовали такие инструменты, как npm, Yarn или Bundler?
  2. Если да, то были ли у вас проблемы из-за того, что npm i , yarn add и bundle update <gem> / bundle add не касаются всех других ваших зависимостей?
  3. Вы считали обременительным запускать npm up , yarn upgrade или bundle update ?

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

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

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

Таким образом, для pipenv мы сознательно руководствуемся принципами мобильных и современных настольных операционных систем (т. Е. Используем по умолчанию автоматические обновления, которых нужно избегать), а не следуем другим менеджерам пакетов и традиционным серверным операционным системам. Дело не в том, что мы не знаем, как это работает, - дело в том, что мы думаем, что типичные результаты традиционного поведения по умолчанию плохие, и хотим их избегать.

Добавление --keep-outdated (и соответствующей переменной среды PIPENV_KEEP_OUTDATED=1 ) позволяет более опытным разработчикам явно сказать: «Я знаю, что делаю, и вы можете доверять мне ответственно управлять своими зависимостями».

Я удалил открытый вопрос --selective-upgrade и включил эти детали в описание предлагаемой функции.

Однако я добавил новый открытый вопрос, связанный с pipenv uninstall . Хотя я готов защищать то, что pipenv install подразумевает pipenv update по умолчанию (согласно приведенному выше обсуждению с @taion), наличие pipenv uninstall do, которое мне кажется значительно менее оправданным - иметь операцию по удалению зависимости, потенциально добавляющую новые транзитивные зависимости из-за обновлений в других компонентах, было бы очень странно.

Что касается открытых вопросов, я не вижу никакого применения pipenv install --skip-lock в мире инструментов автоматического обновления зависимостей. Если нет человеческого варианта использования (я не могу придумать ни одного), я думаю, что можно с уверенностью считать его избыточным.

np использует --no-package-lock (и эквивалент Yarn). Идея состоит в том, чтобы запускать ваши тесты со всеми вашими зависимостями npm, разблокированными до последних совместимых диапазонов, явно игнорируя файл блокировки.

Этот конкретный вариант использования, возможно, менее актуален, учитывая существование tox (и сложность создания чего-либо вроде np для Python), даже в этом случае для чего-то вроде библиотеки имеет смысл иметь как заблокированный набор зависимостей, так что что люди, прыгающие в систему, не должны иметь дело с неработающей средой сборки, и чтобы люди могли тестировать на соответствие новейшим совместимым зависимостям, например, перед выпуском.

Да, я определенно могу увидеть пример использования тестирования, но часть, которая для меня менее очевидна, заключается в том, что в этой ситуации файл блокировки не изменяется (особенно потому, что pipenv update настоящее время не предлагает такой вариант):

  • если это чисто для тестирования в CI, то сервер CI не будет делать git push , поэтому модификации файла блокировки в любом случае не появятся нигде
  • учитывая исходный контроль, вы можете отменить любые изменения файла локальной блокировки, если вы решите, что не хотите их хранить

Также есть pip install --upgrade <whatever> для полного обхода механизма блокировки и объявленных ограничений Pipfile.

Прямо сейчас этот вариант имеет смысл, поскольку это ближайший эквивалент pipenv настоящее время предлагает pipenv --keep-outdated (при этом вы можете добавить что-то в Pipfile без автоматического обновления всего остального).

А пока я оставлю это как открытый вопрос - надеюсь, правильный ответ станет более ясным, когда существуют pip lock --keep-outdated и pip install --keep-outdated .

Ожидается ли, что предлагаемые изменения по-прежнему устранят несоответствия между [packages] и [dev-packages] ? В частности, я столкнулся с № 1220, который относится к этой проблеме, но я не вижу, как предлагаемые изменения собираются исправить это несоответствие. Или несоответствие между разработчиками и другими разработчиками отличается от описанного в # 1220, и следует ли исследовать эту проблему отдельно?

@matthijskooijman Это явно не указано в верхнем сообщении, но https://github.com/pypa/pipenv/issues/1255#issuecomment -354585775 (который упоминается в сообщении как текущий) действительно указывает, что необходимо либо способ «обнаружения (и устранения) несоответствий» в packages и dev-packages , либо необходима альтернатива. Для меня это означает, что несоответствие будет устранено.

Намерение состоит в том, чтобы эта несогласованность была разрешена на шаге pipenv lock (тогда pipenv sync унаследует самосогласованный файл блокировки)

(Примечание: раньше это было непонятно, поэтому я добавил отдельный пункт, называющий этот шаг)

Я только что заметил, что pipenv не восстанавливает файл блокировки, когда вы меняете базовую реализацию python между CPython и PyPy.

  1. Создайте и установите venv с помощью pipenv install --python pypy
  2. удалить венв
  3. Создайте и снова установите venv с помощью pipenv install
  4. Файл блокировки не создается повторно, и раздел host-environment-markers прежнему будет содержать "platform_python_implementation": "PyPy"

@joshfriend Это на самом деле намеренно, но см. https://github.com/pypa/pipenv/issues/857#issuecomment -368223561, чтобы узнать, почему это в настоящее время проблематично.

Сохраните текущее поведение для установки pipenv без аргументов, но переключитесь на рекомендацию использования синхронизации pipenv при настройке новой среды (таким образом установка pipenv используется в основном для изменения установленных компонентов)

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

обновите блокировку pipenv, чтобы всегда гарантировать, что [пакеты] и [dev-пакеты] согласованы друг с другом (разрешение для # 1137)

я только что ударил по этому https://github.com/pypa/pipenv/commit/fdebdc3c423dce83c13d4e384acb703291109f1e

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

исправлены детали реализации. https://github.com/pypa/pipenv/commit/daa56e1290b259af8e2410b2f4d799ca71601a37

@kennethreitz Хороший pipenv install нормально читающего для нового случая установки: он странно читает только в случае повторной синхронизации, когда он может в конечном итоге выполнять обновления и понижения, чтобы версии совпадали. Я пометил пункт о рекомендации pipenv sync как завершенный и вычеркнул те моменты, которые мы решили не менять.

С вашей реализацией изменений # 1137 остаются только улучшения --keep-outdated и --selective-upgrade , которые вместе реализуют # 966.

Учитывая выбранный подход к реализации для # 1486, функция --selective-upgrade должна будет передать --upgrade-strategy=only-if-needed в базовый вызов pip install в дополнение к установке keep_outdated когда обновление устаревшего файла блокировки.

Сейчас работаем над --keep-outdated :)

$ pipenv lock --keep-outdated теперь сохраняет все номера версий из предыдущего файла блокировки, если только номера версий не закреплены.

Также добавлен дополнительный параметр конфигурации Pipfile (в настоящее время у нас есть только allow_prereleases ): keep_outdated :

[pipenv]

keep_outdated = true

--selective-upgrade готово.

Ура! Закрытие этого, так как любые дальнейшие ограничения, которые еще не покрыты # 857, могут быть зарегистрированы как новые проблемы после выпуска 10.1 :)

работает над ошибкой, но будет решена в ближайшее время

фиксированный

Была ли эта страница полезной?
0 / 5 - 0 рейтинги