PythonMiddleTechnical
Что такое lock-файл и зачем он нужен?
Lock-файл (poetry.lock, uv.lock, requirements.txt от pip-compile) фиксирует точные версии и хеши всех зависимостей, включая транзитивные. Нужен для воспроизводимых сборок, безопасности и стабильного CI. Для приложений lock коммитим в git и ставим в проде с --frozen/--require-hashes; в библиотеках — нет.
Что такое lock-файл
Lock-файл — это файл, в котором зафиксированы точные версии всех зависимостей проекта (включая транзитивные) и часто их хеши. В отличие от pyproject.toml/requirements.in, где обычно стоят диапазоны (fastapi>=0.110), lock закрепляет конкретные сборки (fastapi==0.115.2, starlette==0.38.6, …) ровно те, что были разрешены в момент его генерации.
Зачем он нужен
- Воспроизводимость: одинаковая среда в dev/CI/prod и через полгода после релиза.
- Безопасность: хеши в lock защищают от подмены содержимого пакета на PyPI/зеркале.
- Управление транзитивами: исключает «вчера работало — сегодня сломалось» из-за минорного апдейта чужой зависимости.
- Аудит: легко прогнать
pip-audit/safetyпо фиксированному списку.
Инструменты в экосистеме Python
pip-tools:requirements.in→pip-compile→requirements.txt(lock).poetry:pyproject.toml+poetry.lock, командыpoetry lock,poetry install --sync.uv:pyproject.toml+uv.lock, командыuv lock,uv sync; очень быстрая нативная реализация резолвера.pipenv:Pipfile+Pipfile.lock(использование падает).pdm:pyproject.toml+pdm.lock, поддержка PEP 582.
Типовой workflow (pip-tools)
# requirements.in
# fastapi>=0.110
# sqlalchemy[asyncio]>=2.0
uv pip install pip-tools
pip-compile --generate-hashes --resolver=backtracking requirements.in
# создаст requirements.txt c пинами и --hash=sha256:...
# В CI/проде:
pip install --require-hashes -r requirements.txt
# Обновление зависимости:
pip-compile --upgrade-package fastapi requirements.in
Пример с uv
uv init
uv add fastapi sqlalchemy httpx
uv lock # сгенерирует/обновит uv.lock
uv sync --frozen # установит ровно то, что в lock (CI/prod)
uv lock --upgrade-package httpx
Application vs library
- Приложение (сервис, бот, CLI): lock коммитим в git, в проде ставим из lock с
--frozen/--require-hashes. Это норма. - Библиотека (публикуется на PyPI): в
pyproject.tomlдержим широкие диапазоны, lock не публикуем и не навязываем пользователям. Lock можно держать только для собственного CI, чтобы прогонять тесты в воспроизводимой среде.
Подводные камни
- Lock привязан к платформе и интерпретатору: lock, собранный под Linux/CPython 3.12, может не подойти для macOS/3.11 (бинарные wheel разные). Решения: универсальные lock (uv поддерживает multi-platform), пересборка lock в CI под целевую ОС.
- Lock без хешей не защищает от подмены пакета; всегда включайте
--generate-hashesдля prod-сервисов. - Слепое
poetry update/uv lock --upgradeломает прод: обновляйте точечно по пакету и прогоняйте тесты. pip install -r requirements.txtбез--require-hashesи без--no-deps/--constraintможет подтащить более свежие транзитивы — используйтеpip install --require-hashesилиpip-sync.- Lock в Docker должен копироваться до кода (отдельным
COPY pyproject.toml uv.lock ./+uv sync --frozen), иначе ломается кеширование слоёв. - Конфликты при мерже lock — норма. Не правьте файл руками: ресольвьте
pyproject.toml/requirements.in, затем перегенерируйте lock.
Common mistakes
- Говорить, что lock нужен только для скорости.
- Не упоминать transitive dependencies.
- Путать constraints file и lock semantics.
What the interviewer is testing
- Объясняет reproducibility.
- Понимает direct/transitive versions.
- Знает workflow обновления lock.