HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <p>На предыдущем шаге каждая новая установка зависимостей приводила сначала к созданию, а потом и обновлению lock-файла.</p>
1 <p>На предыдущем шаге каждая новая установка зависимостей приводила сначала к созданию, а потом и обновлению lock-файла.</p>
2 <p>Обсудим этот файл подробнее. Как мы уже обсуждали, в файле<em>pyproject.toml</em>указываются зависимости. При этом у каждой зависимости могут быть свои собственные зависимости, которые также обновляются и так до бесконечности.</p>
2 <p>Обсудим этот файл подробнее. Как мы уже обсуждали, в файле<em>pyproject.toml</em>указываются зависимости. При этом у каждой зависимости могут быть свои собственные зависимости, которые также обновляются и так до бесконечности.</p>
3 <p>Зависимости зависимостей называются<strong>транзитивными</strong>, и с ними все не просто. Система зависимостей может быть очень запутанной. Для такой ситуации придумали специальный термин - "ад зависимостей" или<a>dependency hell</a>.</p>
3 <p>Зависимости зависимостей называются<strong>транзитивными</strong>, и с ними все не просто. Система зависимостей может быть очень запутанной. Для такой ситуации придумали специальный термин - "ад зависимостей" или<a>dependency hell</a>.</p>
4 <p>Проблема заключается в том, что мы никак не фиксируем версии транзитивных зависимостей. Представим такой пример:</p>
4 <p>Проблема заключается в том, что мы никак не фиксируем версии транзитивных зависимостей. Представим такой пример:</p>
5 <ul><li>В нашем проекте есть зависимый пакет<strong>A</strong>с зафиксированной версией 1.3.2</li>
5 <ul><li>В нашем проекте есть зависимый пакет<strong>A</strong>с зафиксированной версией 1.3.2</li>
6 <li>У зависимости<strong>А</strong>есть зависимый пакет<strong>B</strong>с версией *</li>
6 <li>У зависимости<strong>А</strong>есть зависимый пакет<strong>B</strong>с версией *</li>
7 </ul><p>uv предоставляет команду uv sync, которая синхронизирует зависимости в проекте с теми, что указаны в<em>pyproject.toml</em>. Так без lock-файла команда uv sync поставила бы:</p>
7 </ul><p>uv предоставляет команду uv sync, которая синхронизирует зависимости в проекте с теми, что указаны в<em>pyproject.toml</em>. Так без lock-файла команда uv sync поставила бы:</p>
8 <ul><li>Для<strong>A</strong>- указанную версию</li>
8 <ul><li>Для<strong>A</strong>- указанную версию</li>
9 <li>Для<strong>B</strong>- последнюю доступную версию из репозитория</li>
9 <li>Для<strong>B</strong>- последнюю доступную версию из репозитория</li>
10 </ul><p>Другими словами, выбор версии не детерминирован. Если автор обновит<strong>B</strong>и нарушит обратную совместимость, то пакет А перестанет работать - весь проект просто сломается.</p>
10 </ul><p>Другими словами, выбор версии не детерминирован. Если автор обновит<strong>B</strong>и нарушит обратную совместимость, то пакет А перестанет работать - весь проект просто сломается.</p>
11 <p>Можно вручную отслеживать зависимости всех зависимостей и явно прописывать их версии в<em>pyproject.toml</em>. Но такой способ вряд ли сработает, потому что пакеты постоянно обновляются и меняются. Еще отслеживать вручную сложно, потому что связей слишком много - даже в проекте с пятью зависимостями будут сотни транзитивных зависимостей.</p>
11 <p>Можно вручную отслеживать зависимости всех зависимостей и явно прописывать их версии в<em>pyproject.toml</em>. Но такой способ вряд ли сработает, потому что пакеты постоянно обновляются и меняются. Еще отслеживать вручную сложно, потому что связей слишком много - даже в проекте с пятью зависимостями будут сотни транзитивных зависимостей.</p>
12 <p>Другой выход - требовать, чтобы создатели всех библиотек всегда указывали версии. Этот вариант тоже не сработает, на этот раз из-за человеческого фактора.</p>
12 <p>Другой выход - требовать, чтобы создатели всех библиотек всегда указывали версии. Этот вариант тоже не сработает, на этот раз из-за человеческого фактора.</p>
13 <p>Есть одно решение, которое точно сработает - это lock-файл. По сути это автоматизированное отслеживание зависимостей. Содержимое lock-файла выглядит примерно так:</p>
13 <p>Есть одно решение, которое точно сработает - это lock-файл. По сути это автоматизированное отслеживание зависимостей. Содержимое lock-файла выглядит примерно так:</p>
14 <p>Первый запуск установки зависимостей сформирует этот файл. Туда запишутся все установленные зависимости, в том числе транзитивные с версиями и<a>хеш-суммами</a>.</p>
14 <p>Первый запуск установки зависимостей сформирует этот файл. Туда запишутся все установленные зависимости, в том числе транзитивные с версиями и<a>хеш-суммами</a>.</p>
15 <p>Так в примере выше, пакет pytest зависит от пакетов colorama, iniconfig, packaging и pluggy. И дальше в лок-файле записана информация об этих пакетах.</p>
15 <p>Так в примере выше, пакет pytest зависит от пакетов colorama, iniconfig, packaging и pluggy. И дальше в лок-файле записана информация об этих пакетах.</p>
16 <p>При дальнейших запусках команда uv sync всегда ставит то, что указано в lock-файле. Это сработает, даже если удалить папку<em>.venv</em>или добавить новые версии пакетов в файл<em>pyproject.toml</em>. Повторный запуск через любой промежуток времени приведет к тому же результату. Теперь с уверенностью можно сказать - проект запустится в любое время и для любого пользователя.</p>
16 <p>При дальнейших запусках команда uv sync всегда ставит то, что указано в lock-файле. Это сработает, даже если удалить папку<em>.venv</em>или добавить новые версии пакетов в файл<em>pyproject.toml</em>. Повторный запуск через любой промежуток времени приведет к тому же результату. Теперь с уверенностью можно сказать - проект запустится в любое время и для любого пользователя.</p>
17 <h2>Версионирование</h2>
17 <h2>Версионирование</h2>
18 <p>Поговорим об обновлении зависимостей. Для обновления всех зависимостей нужно выполнить команду uv sync --upgrade или кратко uv sync -U. Чтобы выполнить обновление конкретной зависимости - uv add -U name, где name - имя библиотеки. А как будет происходить обновление, зависит от того, что написано в pyproject.toml.</p>
18 <p>Поговорим об обновлении зависимостей. Для обновления всех зависимостей нужно выполнить команду uv sync --upgrade или кратко uv sync -U. Чтобы выполнить обновление конкретной зависимости - uv add -U name, где name - имя библиотеки. А как будет происходить обновление, зависит от того, что написано в pyproject.toml.</p>
19 <p>Рассмотрим все доступные варианты:</p>
19 <p>Рассмотрим все доступные варианты:</p>
20 <p>Вариант без указания версии означает, что можно ставить любую версию библиотеки. После выполнения команды обновления в папке .venv окажется последняя доступная версия package</p>
20 <p>Вариант без указания версии означает, что можно ставить любую версию библиотеки. После выполнения команды обновления в папке .venv окажется последняя доступная версия package</p>
21 <p>Если указан конкретный номер через ==, то версия библиотеки жестко зафиксирована и никакая команда не сможет обновить ее</p>
21 <p>Если указан конкретный номер через ==, то версия библиотеки жестко зафиксирована и никакая команда не сможет обновить ее</p>
22 <p>Самый интересный сценарий происходит в случае использования тильды (~).</p>
22 <p>Самый интересный сценарий происходит в случае использования тильды (~).</p>
23 <p>В семантическом версионировании считается, что patch, последняя цифра в версии, изменяется только в случае исправления ошибок, значит, обратная совместимость не должна теряться. При этом на практике это не всегда так. Код может работать с учетом ошибок в зависимостях.</p>
23 <p>В семантическом версионировании считается, что patch, последняя цифра в версии, изменяется только в случае исправления ошибок, значит, обратная совместимость не должна теряться. При этом на практике это не всегда так. Код может работать с учетом ошибок в зависимостях.</p>
24 <p>Как правило, в проектах десятки, а то и сотни зависимостей, причем обновляются они часто. Казалось бы, тогда можно не указывать версию, но тогда обновления нередко могут ломать систему из-за мажорных обновлений библиотек. С другой стороны, можно зафиксировать все версии, и тогда обновлять все придется вручную.</p>
24 <p>Как правило, в проектах десятки, а то и сотни зависимостей, причем обновляются они часто. Казалось бы, тогда можно не указывать версию, но тогда обновления нередко могут ломать систему из-за мажорных обновлений библиотек. С другой стороны, можно зафиксировать все версии, и тогда обновлять все придется вручную.</p>
25 <p>Поэтому появился третий вариант. Добавление тильды приводит к тому, что в автоматическом режиме обновляются только патчи. Предположим что после добавления зависимости в проект, версия была установлена в ~2.10.3. Если после нее разработчики выпустили 2.10.5, то она будет установлена командой обновления.</p>
25 <p>Поэтому появился третий вариант. Добавление тильды приводит к тому, что в автоматическом режиме обновляются только патчи. Предположим что после добавления зависимости в проект, версия была установлена в ~2.10.3. Если после нее разработчики выпустили 2.10.5, то она будет установлена командой обновления.</p>
26 <p>То же самое произойдет, если потом будет выпущена версия 2.10.15. Но если создатель библиотеки опубликует изменения в мажорной и минорной версии, например, 2.11.5 или 3.0.0, то менеджер зависимостей их проигнорирует.</p>
26 <p>То же самое произойдет, если потом будет выпущена версия 2.10.15. Но если создатель библиотеки опубликует изменения в мажорной и минорной версии, например, 2.11.5 или 3.0.0, то менеджер зависимостей их проигнорирует.</p>
27 <p>Примерно то же самое происходит и при использовании сочетания &gt;= , &lt;. Здесь фиксируется только мажорная версия, а минорную и патч разрешено обновлять.</p>
27 <p>Примерно то же самое происходит и при использовании сочетания &gt;= , &lt;. Здесь фиксируется только мажорная версия, а минорную и патч разрешено обновлять.</p>