Должен ли я приписывать версии зависимостей Python?

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

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

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

Я как-то пошел на гибридное решение, где я предположил, что мои зависимости используют семантическое управление версиями и закрепляют только основной номер версии (скажем, somelib >= 2.3.0, < 3), за исключением случаев, когда основной номер версии равен 0 (семантическое управление версиями диктует, что такие версии считаются изменчивыми и могут нарушать API даже при столкновении только с номером патча).

На данный момент я не уверен, какой путь лучший. Есть ли официальное руководство (возможно, даже PEP?), Которое диктует наилучшую практику в отношении зависимостей Python и как их определять?

Ответ 1

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

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

Раздел PEP 426 о семантических зависимостях (метаданные для пакетов программного обеспечения Python) гласит:

"Управление зависимостями в значительной степени зависит от схемы идентификации и спецификации версий, определенной в PEP 440 (PEP 440 - Идентификация версии и зависимостей)".

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

Ответ 2

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

Если вы выпускаете библиотеку в PyPI, вы должны объявлять все зависимости, о которых знаете, но не привязывать к определенной версии. Например, если вы знаете, что вам нужно >= 1.2, но 1.4 сломан, тогда вы можете написать что-то вроде somepkg >= 1.2, != 1.4. Если одна из вещей, которую вы знаете, это то, что somepkg следует за SemVer, вы можете добавить < 2.

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

Обратите внимание, что эти два совета дополняют друг друга: это просто факт, что если приложение A, использующее библиотеку B, то либо автор A, либо автор B могут связывать зависимости B, но не оба. Поэтому мы должны выбрать один. Основной принцип здесь заключается в том, что это лучше всего сделать как можно позже, т.е. Автором А, который может видеть всю свою систему; работа библиотеки B состоит в том, чтобы передать некоторые полезные подсказки, чтобы помочь A принять эти решения. В частности, если все библиотеки, которые A зависят от записи, точно знают, что они знают об их лежащих в основе зависимостях, тогда A может сделать разумные решения о том, что делать, когда они перекрываются. Например, если зависимость B зависит от requests >= 1.0, != 1.2, а зависимость C зависит от requests >= 1.1, то мы можем предположить, что 1.1 или 1.3 могут быть хорошими версиями для вывода. Если зависимость B зависит от requests == 1.1 а зависимость C зависит от requests == 1.2, тогда мы просто застряли.

Ответ 3

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

Зачем? Подробное исследование разрешения зависимостей Python, проанализировав десятки тысяч пакетов PyPI и их текущие уровни конфликтов зависимостей, обсуждает эту проблему. В нем объясняется, что:

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

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

Он советует:

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