2025, Nov 01 17:46
Офлайн установка sdist с pip: как обойти ошибку setuptools
Почему pip в офлайне не находит setuptools из-за изоляции сборки. Два решения: локальные wheels через --find-links или установка с --no-build-isolation.
Изолированные от сети (air‑gapped) или жестко ограниченные серверы хороши с точки зрения безопасности, но в них проявляется острый угол экосистемы пакетов Python. Вы можете заранее установить все зависимости времени выполнения, добавить свой исходный дистрибутив — и всё равно увидеть, как pip падает с жалобой на то, что не находит setuptools, хотя импорт в Python успешно работает. Корень проблемы — изоляция сборки, и хорошая новость в том, что это можно корректно исправить без открытия сетевого доступа.
Воспроизводим проблему
На офлайн‑машине установка локального sdist с помощью pip при полном блокировании удалённых индексов выглядит так:
pip3 install --no-deps --no-index acme_pkg-1.0.0.tar.gzУстановка прерывается сообщением примерно такого вида:
× подпроцесс pip для установки зависимостей сборки завершился с ошибкой.
│ код возврата: 1
╰─> [2 строки вывода]
ERROR: Не удалось найти версию, удовлетворяющую требованию setuptools>=57 (доступные версии: нет)
ERROR: Подходящих дистрибутивов для setuptools>=57 не найдено
При этом внутри Python импорт setuptools проходит и сообщает подходящую версию. Вот что сбивает с толку.
Что на самом деле происходит
Когда pip собирает пакет из исходников, он использует изоляцию сборки. Создаётся временная виртуальная среда, туда устанавливаются объявленные зависимости для сборки, затем пакет собирается, а окружение удаляется. Глобальный setuptools вашей системы в /usr/lib/python3/dist-packages в этом изолированном шаге не участвует. Поскольку вы передали --no-index, pip отказывается обращаться к каким‑либо репозиториям за зависимостями для этой эфемерной среды. Без локального wheel, который можно установить в этот «песочницу», сборка завершается ошибкой «No matching distribution found for setuptools».
Два проверенных способа решения
Первый подход — заранее получить инструменты сборки на подключённой к интернету машине и сделать их доступными локально для офлайн‑хоста. На машине с доступом в сеть скачайте нужные колёса (wheels):
pip download setuptools wheelСкопируйте загруженные файлы .whl на офлайн‑сервер и установите свой пакет, указав pip на эту локальную директорию. Индекс оставьте отключённым, чтобы ничего не пыталось уйти в сеть:
pip install --find-links /srv/wheels/ --no-index acme_pkgВторой подход — полностью обойти временное окружение. Если вы уверены, что на целевой системе уже есть всё необходимое, можно указать pip не использовать изоляцию сборки. Тогда сборка пройдёт в текущем окружении, используя уже установленный setuptools:
pip install --no-index --no-build-isolation acme_pkgЕсли есть сомнения, к какому интерпретатору Python привязан ваш pip, запускайте pip через сам интерпретатор, чтобы избежать несоответствий:
python -m pip install --no-index --no-build-isolation acme_pkgПочему это важно
В ограниченных средах критична детерминистичность установок. Для подключённых систем изоляция сборки — разумное значение по умолчанию, но офлайн она превращается в ловушку, если заранее не подготовить зависимости сборки. Понимание того, что pip выполняет сборку внутри кратковременной среды, объясняет, почему импорт проходит успешно, тогда как установщик утверждает, что зависимость отсутствует. Как только вы либо предоставляете локальные колёса через --find-links, либо отключаете изоляцию сборки, процесс вновь становится предсказуемым.
Итоги
На изолированных хостах заранее подготовьте всё для сборок. Либо отзеркальте необходимые колёса для сборки — такие как setuptools и wheel — на подключённой машине и укажите pip на этот запас через --find-links и --no-index, либо отключите изоляцию сборки, если контролируете окружение и знаете, что нужные инструменты уже установлены. Чтобы исключить неоднозначность интерпретатора, запускайте все установки через python -m pip. С этими настройками установка вашего пакета из локального .tar.gz проходит гладко и без компромиссов для сетевой политики.
Материал основан на вопросе на StackOverflow от Bill Shubert и ответе пользователя phd.