Pip: Решение проблем, связанных со сборками вне дерева

Созданный на 4 янв. 2020  ·  68Комментарии  ·  Источник: pypa/pip

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

Какую проблему решит эта функция?

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

Этот подход со временем вызвал ряд проблем:

  • Когда setup.py / pyproject.toml не находится в корне проекта и когда сборка зависит от ресурсов вне поддерева setup.py / pyproject.toml (# 3500, # 7549, # 6276), например:

    • сборке нужны ресурсы, которые являются символическими ссылками на файлы / каталоги вне поддерева

    • build требуется репозиторий git (например, при использовании setuptools_scm), а .git / находится в родительском каталоге, а не копируется во временный каталог с помощью pip

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

  • Проблемы с производительностью при большом каталоге проекта (№ 2195).

Почему pip копирует во временный каталог перед сборкой? Предостережение: мне это непонятно - вот что я пока собрал:

  • Чтобы не полагаться на что-то вне источника (https://github.com/pypa/pip/issues/2195#issuecomment-524606986), хотя определение «вне источника» является причиной некоторых проблем выше
  • Чтобы избежать загрязнения исходного каталога артефактами сборки или остатками (?)
  • Что-то другое?

Возможные решения

  1. Создайте sdist на месте, распакуйте sdist во временном месте, затем выполните сборку из него.
  2. Добавьте вариант пипса для сборки на месте.
  3. Обновите PEP 517, добавив в него какой-то механизм, позволяющий серверным компонентам обмениваться данными с интерфейсными модулями, если они «безопасны» для сборки на месте.
  4. Измените пип, чтобы он всегда оставался на месте.
  5. Измените pip, чтобы он был встроен по умолчанию, с возможностью построения вне дерева.

Дополнительный контекст

Подробнее о сборке с помощью sdist можно прочитать на сайте Discussion.python.org .

needs discussion

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

Исходя из https://github.com/pypa/pip/issues/2195#issuecomment -664728481, я могу сказать, что я более чем счастлив переделать # 7882 за --use-feature=in-tree-build .

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

Глядя на это с точки зрения серверной части, идея «сборки вне дерева» на самом деле бессмысленна. Серверной части предоставляется «дерево исходных текстов» в виде текущего каталога процесса, и его просят выполнить сборку. У него нет возможности узнать, был ли этот каталог извлечен из sdist, извлечен из VCS или скопирован из другого места. Все, что он может сделать, это построить, и, если у него нет того, что нужно для сборки, сообщить об ошибке.

Так что в значительной степени убивает возможное решение (3) ИМО - бэкенд не имеет понятия , что такое строить на месте есть, так что не могу сказать , является ли такая сборка безопасна 1.

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

Сказав это, я не против того, чтобы pip просто строился на месте. Я считаю, что причина, по которой мы этого не делаем, заключается в том, что у нас были случаи, когда артефакты, оставшиеся от предыдущей сборки, использовались в последующей сборке, но были построены с другими параметрами (например, объектные файлы, созданные в режиме отладки, были связаны с сборкой выпуска сделано из того же дерева). Однако разумно сказать, что бэкенды должны гарантировать, что таких проблем не произойдет, и если они возникнут, это ошибка бэкэнд, а не пип, чтобы попытаться от нее защититься. Однако я не уверен, что такая позиция особенно удобна для пользователя - это возникло во время обсуждений PEP 517 в рамках темы инкрементных сборок и было достаточно спорным, что в то время было отложено.

Я предпочел создать sdist, а затем построить колесо из него уже долгое время (ваш вариант 1). Я согласен с созданием pip (если мы можем согласиться с тем, что это безопасно, учитывая, что, как я отмечал выше, мы не можем ожидать, что серверная часть сообщит нам об этом), но я думаю, что для этого потребуется сообщество обсуждение, чтобы обсудить более широкие последствия (для бэкэндов, pip / frontend и конечных пользователей).

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

Я добавил решения 4. (Изменить pip, чтобы всегда строить на месте) и 5. (Изменить pip для сборки на месте по умолчанию с возможностью построения вне дерева).

У меня смешанные чувства относительно сборки с помощью sdist (решение 1.) по следующим причинам:

  1. в некоторых проектах может быть нарушен путь sdist-to-wheel; хотя я вижу ценность проверки работоспособности сборки из sdists, выполнение этого по умолчанию сейчас наверняка сломает множество сборок для конечных пользователей.
  2. он по-прежнему влияет на производительность для проектов с большими sdist и из-за дополнительных вызовов подпроцесса
  3. Я лично считаю, что нам не следует уделять слишком много внимания sdist, поскольку для проектов довольно часто публикуются построенные артефакты и ссылаются на свою любимую платформу хостинга кода для своих исходных выпусков (например, бэкенды, которые полагаются на наличие проверки VCS для здание нужно перепрыгивать через обручи, чтобы получился рабочий сдист). И PEP 517 специально позволяет серверным приложениям собирать UnsupportedOperation за build_sdist .

В этом посте на обсуждение также резюмируются аналогичные аргументы.

Я согласен, что путь решения 3. далеко не очевиден.

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

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

  • Создайте sdist на месте, распакуйте sdist во временном месте, затем выполните сборку из него.

Думаю, это хороший подход.

Скорее всего, IMO это будет запускаться для одного пакета в большинстве запусков pip install с участием локальных каталогов - чаще всего я представляю pip install . . Вероятно, это будет сделано в рамках рабочего процесса разработки пакета.

Вот каким, я думаю, должно быть такое поведение:

  • Если бэкэнд не может создать sdist, выполните local-dir -> wheel (на месте)

    • Я думаю, что в этом случае ответственность за то, чтобы local-dir -> wheel была идемпотентной операцией, ложится на бэкэнд.

  • Если бэкэнд может создавать sdist, выполните local-dir -> sdist -> unpacked-sdist -> wheel.

Выполняя local-dir -> sdist -> wheel, у нас действительно есть дополнительный набор вызовов. Тем не менее, я думаю, что разумно подтвердить, что сгенерированные sdist являются нормальными, особенно во время разработки. tox уже делает это как часть своего рабочего процесса, проверьте манифест, чтобы скрыть не очень дружественные интерфейсы setuptools.

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

Что касается развертывания, я думаю, мы хотели бы подождать и посмотреть, как появится # 6536. Мы определенно узнаем несколько вещей, которые можно перенести.

Я предпочитаю сборку / установку на месте без sdist (поэтому setup.py install или setup.py bdist_wheel или вызов build_wheel на бэкэнде PEP 517, если применимо) вместо создания sdist, распаковки и установки От этого. Мои конкретные причины:

  1. Поддерживает наибольшее количество пользователей из коробки.

    1. Предположим, что pip выполняет local-dir -> installed (через сборку колеса на месте или setup.py install ). Пользователи, которые хотят перейти из local-dir -> installed, могут выполнить pip install local-dir . Пользователи, желающие перейти из local-dir -> sdist -> installed, могут создать sdist и затем выполнить pip install ./path/to/sdist . Существует множество альтернативных инструментов, с помощью которых можно создать sdist, и это то, что пользователи, скорее всего, уже будут иметь, если они не будут вручную создавать дистрибутивы, которые загружают в PyPI.

    2. Теперь предположим, что pip выполняет local-dir -> sdist -> installed. Пользователи, которые хотят перейти из local-dir -> installed, не имеют опций, связанных с pip. Пользователи, желающие перейти из local-dir -> sdist -> installed, могут выполнить pip install local-dir . Пользователи без параметров будут запрашивать у pip параметры для управления поведением или должны будут найти другой инструмент, который в противном случае им бы не понадобился.

  2. Если мы реализуем local-dir -> sdist -> installed, предположительно, мы также сделаем это для требований на основе VCS? Если так, то это больше работы. Если нет, то это дополнительные пути в коде и отклонения в способе обработки установки, которые должны быть запомнены пользователями или при предоставлении поддержки.
  3. Наименьший объем работы для выполнения. Есть три места, которые нужно изменить, чтобы реализовать local-dir -> installed ( здесь , здесь и здесь ). Для установки local-dir -> sdist -> я бы даже не хотел касаться реализации этого, пока не будет выполнен # 6607, иначе я думаю, что это закончится во многих местах в базе кода, аналогичных загрузке артефактов / проверке хэша.
  4. Наименьший объем работы для тестирования, поскольку, IMO, существующих тестов достаточно, чтобы покрыть путь кода local-dir -> установленный. Для пути local-dir -> sdist -> installed мы хотели бы убедиться, что мы действительно создаем sdist, и что резервные варианты работают для создания колеса напрямую.
  5. Наименьший объем работы (в вычислительном отношении). Как упоминалось в другом месте, local-dir -> sdist -> installed - это дополнительный вызов подпроцесса (и этот подпроцесс выполняет свою работу). Это также означает, что pip должен распаковать sdist (приветственные сканеры вирусов и другие медленные диски) перед сборкой колеса.

Независимо от подхода, единственная проблема, которую я вижу при выполнении операций на месте, заключается в том, что для сборок setuptools (я думаю, это применимо к устаревшим версиям и PEP 517) мы получим .egg-info в каталоге проекта, что будет ошибочно как «установленный пакет», когда pip вызывается с python -m pip в этом каталоге. Это будет исправлено с помощью # 4575, который предположительно НЕ будет включать текущий каталог в запрос установленных пакетов для любой схемы.

Отмечая, что я пришел к согласию с тем, что идея пропустить сборку sdist и напрямую выполнить сборку в дереве - лучший подход для pip, который следует использовать по умолчанию, а не пытаться делать local-dir -> sdist -> wheel.

В Fedora, когда мы создаем RPM-пакеты Python, мы динозавры, и стандартный способ сделать это - использовать python setup.py build . В PEP 517 мы добавили «предварительный» способ использования вместо этого pip wheel . Однако с модулями расширения у нас есть проблема с подходом «переместить источники в tmp, построить оттуда», который pip использует для их создания.

Наш механизм сборки внедряет некоторые флаги компилятора, поэтому артефакты сборки (в данном случае .so модули расширения) содержат метаданные об их источниках. Позже есть сценарий оболочки, который просматривает артефакты сборки, извлекает эту информацию и копирует источники в /usr/src/debug для установки через специальный *-debugsource RPM. Машиностроение ожидает, что все будет построено в рамках рабочего дерева, и оно не очень хорошо работает, когда построено снаружи. Вот что можно сделать (вместе), чтобы смягчить проблему с нашей стороны:

  1. установите переменную окружения $TMPDIR чтобы она находилась в том месте, где ее ожидает сценарий RPM (т.е. export TMPDIR=%{_builddir}/.tmp (и создайте его))
  2. используйте pip wheel с опцией --no-clean чтобы сохранить скопированные источники в $TMPDIR
  3. запустите оболочку кунг-фу, чтобы переписать информацию «каков мой источник» в правильное место: find %{buildroot} -iname '*.so' -print0 | xargs --no-run-if-empty -0 -n1 /usr/lib/rpm/debugedit -b "%{_builddir}/.tmp/pip-req-build-"* -d "$PWD"
  4. (Необязательно: очистите $TMPDIR вручную.)

Нам не особенно нравится третий шаг, потому что он зависит от слишком большого количества деталей реализации:

  • /usr/lib/rpm/debugedit API и местоположение (и наличие)
  • имя pip-req-build
  • механизм, с помощью которого pip строит исходники

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

Последующий отчет: https://bugzilla.redhat.com/show_bug.cgi?id=1806625

Отмечая, что я пришел к согласию с тем, что идея пропустить сборку sdist и напрямую выполнить сборку в дереве - лучший подход для pip, который следует использовать по умолчанию, а не пытаться делать local-dir -> sdist -> wheel.

Я также все больше склоняюсь к идее сборки колес на месте. Мои оставшиеся бронирования:

  1. Мы бы полагались на то, что серверная часть ведет себя «правильно» - например, не дает разных результатов на основе данных, оставшихся от предыдущих сборок, или чего-то еще. Я согласен с этим предположением, но меня беспокоит стоимость поддержки, если мы начнем получать от людей, говорящих «пип построил мое колесо неправильно», и нам нужно отлаживать только для того, чтобы обнаружить, что это проблема с серверной частью.
  2. Я думаю, что какой бы подход мы
  3. Как следствие вышеизложенного, мы должны убедиться, что нет известных нам проектов, основанных на нашем текущем подходе «копировать и строить», как будто они есть, мы сломаем их этим изменением.

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

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

Имеет ли смысл расширить интерфейс PEP 517, включив в него «чистый» хук? В любом случае мы, вероятно, захотим, чтобы это было точкой для других усилий (например, реализация редактируемой установки, создание инструмента разработки пакетов, который собирает любой проект PEP 517). pip может вызвать его здесь, чтобы убедиться, что перед выполнением сборки в дереве не осталось мусора.

Имеет ли смысл расширить интерфейс PEP 517, включив в него «чистый» хук?

Может быть? Но если pip автоматически вызывает clean , обязательно найдется кто-то, кто не захочет этого делать, делать инкрементные сборки или что-то в этом роде. И тогда мы получаем другой вариант.

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

  1. Мы бы полагались на то, что серверная часть ведет себя «правильно» - например, не дает разных результатов на основе данных, оставшихся от предыдущих сборок, или чего-то еще.

Я бы хотел расширить PEP-517, сделав это явным требованием.

Я бы хотел расширить PEP-517, сделав это явным требованием.

Уже сказано следующее:

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

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

Пытаясь найти обходной путь для Fedora, мы столкнулись с https://github.com/pypa/pip/issues/7872

Поскольку мы решили проблему ".egg-info in cwd" с # 7731 и друзьями, это на одну вещь меньше, о чем нужно беспокоиться при сборке на месте.

Таким образом, вариант 4 (всегда на месте) был реализован в # 7882.

Сейчас (за # 7951) мы опубликовали бета-версию pip, pip 20.1b1. В этот выпуск входит № 7882, в котором реализовано решение этой проблемы.

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

Я также приветствую положительные отзывы типа «ура, теперь работает лучше!» также, поскольку система отслеживания проблем обычно полна «проблем». :)

Мы полностью планируем протестировать его в Fedora (мы уже планировали это до вашего комментария), однако крайний срок во вторник, вероятно, нереален.

@hroncok Есть идеи, когда Fedora сможет протестировать эти изменения?

Я постараюсь сделать это как-нибудь в понедельник, но не могу ничего обещать.

Действительно, 20.1b1 устраняет наши проблемы.

Более общие отзывы о 20.1b1 в https://mail.python.org/archives/list/[email protected]/message/5EAUIYYIRKXEHTAG5GQ7EJHSXGZIW2F7/

Ура! Большое спасибо за то, что попробовали бета-версию @hroncok! Очень признателен! ^> ^

Один из результатов сборки: я параллельно собирал колеса для нескольких версий python (внутри контейнера докеров manylinux). При локальных сборках параллельные сборки не работают, поскольку разные версии конфликтуют. При сборках вне дерева каждая версия создавала отдельное дерево и не имела проблем.

@manthey это обсуждение находится под # 8168

Так что прошло уже больше 10 дней. По поводу изменения было поднят несколько вопросов (я бы сказал, все ожидаемые - # 8165, # 8168, # 8196). Были также люди, прямо упоминавшие, что изменение им помогает.

  • Помимо проблем с производительностью, предыдущее поведение (копирование во временный каталог) имело проблемы с правильностью (см. Ссылку выше), которые невозможно исправить с помощью pip без знания контекста, которое есть только у вызывающего абонента (и, как примечание, этот код дерева копирования уже был заполнен бинты, чтобы справиться со странными ситуациями - tmpdir в дереве, сокетах и ​​т. д.).
  • Возможность активировать предыдущее поведение по-прежнему будет иметь проблемы с корректностью и производительностью.
  • Правильное решение будет включать внутреннюю поддержку сборки для управления каталогом сборки, который на сегодняшний день не существует полностью (например, setuptools bdist_wheel имеет --bdist-dir , но по-прежнему записывает .egg-info в см. также https://github.com/pypa/setuptools/issues/1816, https://github.com/pypa/setuptools/issues/1825). Итак, теперь, когда pip ведет себя правильно, возможно, обсуждение может сместиться, чтобы увидеть, могут ли, например, setuptools развить опцию для выполнения сборки, не касаясь исходного каталога, а затем посмотреть, требуется ли изменение PEP 517 или нет для управления этой опцией.
  • Между тем, вызывающие программы могут относительно легко обойти проблемы, о которых сообщают (например, скопировав себя во временный каталог или создав временный архив, что они могут сделать правильно, зная контекст).
  • Наконец, по имеющимся у нас данным трудно сказать наверняка, но моя интуиция подсказывает, что это изменение помогает большему количеству людей, чем причиняет вред.

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

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

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

Я использовал термин «правильно», потому что до того, как pip wheel <localdir> и pip install <localdir> генерировали колесо, отличное от cd <localdir> ; setup.py bdist_wheel в некоторых случаях: с разными отсутствующими файлами при наличии символических ссылок (# 3500), или другую версию с setuptools_scm (# 7549), или https://github.com/pypa/pip/issues/7555#issuecomment -595180864, ​​или # 6276, или простые ошибки. Я не думаю, что pip 20.1 генерирует такие плохие колеса / установки, поэтому в этом смысле я считаю, что это действительно более правильно.

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

И он по-прежнему может производить колеса, отличные от setup.py sdist && pip install dist/*.tar.gz .

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

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

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

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

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

Я все еще согласен, что проверка sdists желательна, но не во время установки pip. Возможно, это особенность будущего инструмента построения sdist или команды сборки pip.

Кроме того, setup.py sdist создает .egg-info в локальном каталоге, поэтому проблемы с исходным каталогом, доступным только для чтения, или параллельными сборками останутся.

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

Некоторые проблемы с производительностью действительно могут возникнуть снова, если / при сборке через sdist, но они, вероятно, будут на порядок ниже, чем у нас в pip <20.1. Действительно, большая часть этого часто возникала из-за копирования .git , или venv , или другого несвязанного объемного материала, которого не было бы в sdist.

Независимо от того, чем в конечном итоге окажется pip , можем ли мы сделать другой вариант, поскольку он вряд ли сможет удовлетворить всех? Я полагаю, что если текущий подход должен быть сохранен (у меня действительно нет мнения о том, какой должен быть по умолчанию), мы должны иметь возможность предоставить запасной вариант с последним результатом, где пользователь может выбрать создание sdist и установку пакет оттуда.

Кроме того, setup.py sdist создает .egg-info в локальном каталоге, поэтому сообщенные проблемы с исходным каталогом только для чтения или параллельными сборками останутся.

Я думаю (по крайней мере, быстрый тест со мной согласен), что это делает только setuptools (не distutils ), и это поведение можно настроить для создания каталога в другом месте. Как и в случае с другими бэкэндами, мы можем порекомендовать им создать чистую генерацию sdist.

FWIW, я не думаю, что нам нужно будет сбрасывать каталог sdist-generation --egg-info в рабочий каталог, если мы перейдем к подходу generate-sdist-unpack-it-build-wheel, поскольку мы можем сбросьте это во временный каталог, как мы это делаем для generate_metadata .

@pradyunsg, разве это не требует изменения в sdist не было возможности указать базовое местоположение .egg-info , в отличие от egg_info которого есть опция --egg-base которую мы использовали в № 7978.

Действительно! Я искал не тот файл в setuptools. 🙈 Я поправляюсь.

Почему в этом пространстве все так сложно? :(

$  ls -la
total 8
drwxr-xr-x  3 dstufft  staff   96 May  6 14:26 .
drwxr-xr-x  9 dstufft  staff  288 Apr 28 15:46 ..
-rw-r--r--  1 dstufft  staff   85 Apr 23 16:23 setup.py

$  py setup.py egg_info --egg-base /tmp/foo sdist
/Users/dstufft/.pyenv/versions/3.8.2/lib/python3.8/site-packages/setuptools/dist.py:471: UserWarning: Normalizing '2020.04.23.3' to '2020.4.23.3'
  warnings.warn(
running egg_info
creating /tmp/foo/dstufft.testpkg.egg-info
writing /tmp/foo/dstufft.testpkg.egg-info/PKG-INFO
writing dependency_links to /tmp/foo/dstufft.testpkg.egg-info/dependency_links.txt
writing top-level names to /tmp/foo/dstufft.testpkg.egg-info/top_level.txt
writing manifest file '/tmp/foo/dstufft.testpkg.egg-info/SOURCES.txt'
reading manifest file '/tmp/foo/dstufft.testpkg.egg-info/SOURCES.txt'
writing manifest file '/tmp/foo/dstufft.testpkg.egg-info/SOURCES.txt'
running sdist
warning: sdist: standard file not found: should have one of README, README.rst, README.txt, README.md

running check
warning: Check: missing required meta-data: url

warning: Check: missing meta-data: either (author and author_email) or (maintainer and maintainer_email) must be supplied

creating dstufft.testpkg-2020.4.23.3
copying files to dstufft.testpkg-2020.4.23.3...
copying setup.py -> dstufft.testpkg-2020.4.23.3
Writing dstufft.testpkg-2020.4.23.3/setup.cfg
creating dist
Creating tar archive
removing 'dstufft.testpkg-2020.4.23.3' (and everything under it)

$ ls -la                                        
total 8
drwxr-xr-x  4 dstufft  staff  128 May  6 14:28 .
drwxr-xr-x  9 dstufft  staff  288 Apr 28 15:46 ..
drwxr-xr-x  3 dstufft  staff   96 May  6 14:28 dist
-rw-r--r--  1 dstufft  staff   85 Apr 23 16:23 setup.py

https://github.com/pypa/pip/issues/8165#issuecomment -624669107 это похоже на красивую ошибку остановки шоу, возможно, не нашу ошибку, но это один из типов ошибок, который, как я утверждал, может произойти во время обсуждения PEP 517, когда делать сборки на месте по умолчанию.

bdist_wheel раньше просили автоматически очистить каталог сборки. Эта функция должна быть включена. Остальные сборки distutils чисты?

Если бы это был SCons, он запомнил бы файлы, о которых он заботился, и пропустил бы лишние файлы в каталоге build / колеса, даже если они присутствовали в файловой системе.

Я считаю, что вышеупомянутая проблема затрагивает не только manylinux. Это должно происходить каждый раз, когда каталог сборки недостаточно конкретен для захвата ABI (в случае с setuptools кажется, что платформа и версия python - это все, что записано в теге ABI в каталоге сборки). Я думаю, что это выходит за рамки ABI с текущим интерпретатором, если что-то связано, например, с NumPy, я думаю, что у него есть ABI, который будет работать на более новом, но не более старом NumPy, и если они не закодируют это в именовании каталога сборки, тогда это будет эффект тоже используется.

Автоматическая очистка каталога сборки не решает проблему, она просто снижает ее вероятность (например, запуск двух параллельных вызовов pip wheel может вызвать проблему), вдобавок к этой одной из предполагаемых причин для реализации Таким образом (по крайней мере, во время обсуждения PEP 517) было то, что это обеспечит большую производительность, разрешив кэширование между вызовами для инкрементных сборок. IOW текущее поведение - это то, что хотели некоторые подмножества, многократное использование артефактов сборки между запусками, просто так получилось, что наиболее распространенный бэкэнд сборки делает это очень неправильно (и, возможно, в некоторых случаях не хватает информации, чтобы сделать это правильно без каждого настройка пакета).

Конечно, имея достаточное количество флагов для базовой команды setuptools вы можете исправить это (что-то вроде py setup.py egg_info --egg-base /tmp/foo build --build-base /tmp/foo/build-base bdist_wheel --bdist-dir /tmp/foo/bdist сделает это).

Я хотел бы повторить, что проблема не в дополнительных файлах, а в том, что ожидаемый ABI, с которым было совместимо колесо, изменился, а .so не был восстановлен. Если SCons достаточно умен, чтобы знать, что Python, созданный с помощью pymalloc, нуждается в одном каталоге сборки, а Python, созданном с помощью другого (включая такие вещи, как версии NumPy, на которые может ссылаться .so ), это не повлияет. Если он будет повторно использовать ранее созданный артефакт с другим ABI, это повлияет на него.

Я попытался протестировать энконы, но мне не удалось заставить rsalette построить без ошибок.

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

Прохладный. Извините, к сожалению, Enscons обновился, а rsalette - нет.

В среду, 6 мая 2020 г., в 16:18 Дональд Стаффт написал:

Я попытался протестировать энконы, но мне не удалось заставить rsalette построить без ошибок.

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

-
Вы получили это, потому что прокомментировали.
Ответьте на это письмо напрямую, просмотрите его на GitHub https://github.com/pypa/pip/issues/7555#issuecomment-624867490 или откажитесь от подписки https://github.com/notifications/unsubscribe-auth/AABSZERIEDAPUIXCPAKBBUDRQHAXRANCNFSM4 .

Извините, к сожалению, Enscons обновился, а rsalette - нет.

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

Единственная проблема с rsalette заключается в том, что он не должен передавать ROOT_IS_PURELIB в Environment в SConstruct. У него нет расширения C. cryptacular выглядит нормально.

# 8165 (комментарий)

Думаю, я согласен с тем, что мы должны отменить это изменение.

Я думаю, что новые проблемы намного больше, чем ожидалось. Возможно, нужно быстро вернуться к 20.1.1, а затем мы сможем более подробно обсудить, как решить обе проблемы - сборки в дереве и вне дерева?

Я также голосую за возврат и использование https://discuss.python.org/t/proposal-adding-a-persistent-cache-directory-to-pep-517-hooks/2303/15 в качестве решения для этого (что бы разрешить сборку бэкэндов не на месте, поэтому не выявляйте такие проблемы). Присоединяйтесь к этой теме, если вы согласны с предложением.

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

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

Хорошо! Я думаю, что общее мнение состоит в том, чтобы вернуться и переоценить. Я запишу на это пиар. :)

Присоединяйтесь к этой теме, если вы согласны с предложением.

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

Просто сбросил пару больших кляксов текста в https://github.com/pypa/pip/issues/8165#issuecomment -625401463. На сегодня я уйду ... В конце концов, я немного расстроился, когда писал личные заметки в конце. Окончание на # 5599 и чтение отрицательных комментариев пользователей определенно не помогли.

Привет, ребята, я еще подумал об этом, вот моя текущая точка зрения по этому поводу.

  1. Создайте sdist на месте, распакуйте sdist во временном месте, затем выполните сборку из него.

Я все еще считаю, что pip install / pip wheel - не то место, чтобы пытаться поймать плохих sdists. Разве это не должно быть обязанностью серверной части в первую очередь не создавать плохих sdist? Более того, я бы подумал, что безусловная сборка через sdist, вероятно, столь же разрушительна, как и сборка на месте.

  1. Добавьте вариант пипса для сборки на месте.

Тот, который мне больше всего нравится в краткосрочной перспективе, так как решение 4 не помогло. Это преждевременно добавлять в пункт 20.1.1?

  1. Обновите PEP 517, добавив в него какой-то механизм, позволяющий серверным компонентам обмениваться данными с интерфейсными модулями, если они «безопасны» для сборки на месте.

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

  1. Измените пип, чтобы он всегда оставался на месте.

Так что это считается слишком разрушительным, и мы вернемся в 20.1.1.

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

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

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

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

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

Я имею в виду, что у нас есть несколько "путей", по которым может пройти установка:

  1. VCS -> Sdist -> Wheel -> Установлено
  2. VCS -> Колесо -> Установлено
  3. VCS -> Установлено (устаревшее)

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

Мы можем считать, что sdist или wheel загружаются в PyPI и устанавливаются из него, пока не станут частью того же «пути», вы просто приостанавливаете его и завершаете на другом компьютере.

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

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

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

В основном я согласен с @dstufft , и, в частности, я согласен с тем, что подход build-from-sdist следует рассматривать не как «попытку проверки sdist», а как «все следует за» деревом исходных текстов -> sdist -> wheel -> install route (просто некоторые вещи пропускают некоторые начальные шаги) ».

Однако я хочу остановиться на одном моменте:

Что, если я перечислю два пакета, которые находятся в моей локальной FS, и мне нужно создать один на месте, а другой нет?

Просто запустите два пакета в двух отдельных запусках pip с разными параметрами?!? Я знаю, что, возможно, один из них зависит от другого, и ваша точка зрения в целом верна, но люди, похоже, в целом склонны предполагать, что каждый сценарий установки должен быть свернут в один запуск пипса, и я не делаю этого. Думаю, это разумно (у нас есть отличные обходные пути для проблем, которые отклоняются пользователем, потому что «это означает, что мне придется разделить свой список требований на две части»)

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

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

Если новый преобразователь учитывает то, что уже установлено, тогда pip install foo bar и pip install foo && pip install bar будут примерно равны и не имеют никакого значения, но если это не так (и сейчас то же самое примерно верно) если оба проекта зависят от "спама", но foo требуется <2, а bar required> 1, то мы получим неверную установку.

Хотя это касательная :)

(Я не уверен, изменит ли это новый преобразователь?)

Добро пожаловать на # 7744. :)

  1. Измените пип, чтобы он всегда оставался на месте.

Так что это считается слишком разрушительным, и мы вернемся в 20.1.1.

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

  1. Добавьте вариант пипса для сборки на месте.

@dstufft @pfmoore Я рассматриваю такой вариант как механизм https://github.com/pypa/pip/issues/8165#issuecomment -625501216

Я запишу на это пиар. :)

8221 это так.

Был выпущен 20.1.1, содержащий отмененные изменения.

В Fedora, когда мы создаем RPM-пакеты Python, мы динозавры, и стандартный способ сделать это - использовать python setup.py build . В PEP 517 мы добавили «предварительный» способ использования вместо этого pip wheel . Однако с модулями расширения у нас есть проблема с подходом «переместить источники в tmp, построить оттуда», который pip использует для их создания.

Наш механизм сборки внедряет некоторые флаги компилятора, поэтому артефакты сборки (в данном случае .so модули расширения) содержат метаданные об их источниках. Позже есть сценарий оболочки, который просматривает артефакты сборки, извлекает эту информацию и копирует источники в /usr/src/debug для установки через специальный *-debugsource RPM. Машиностроение ожидает, что все будет построено в рамках рабочего дерева, и оно не очень хорошо работает, когда построено снаружи. Вот что можно сделать (вместе), чтобы смягчить проблему с нашей стороны:

1. set the `$TMPDIR` environment variable to have it within the place where the RPM script expects it (i.e. `export TMPDIR=%{_builddir}/.tmp` (and create it))

2. use `pip wheel` with the `--no-clean` option to keep the copied sources in `$TMPDIR`

3. run some shell kung fu to rewrite the "what is my source" information to the correct location: `find %{buildroot} -iname '*.so' -print0 | xargs --no-run-if-empty -0 -n1 /usr/lib/rpm/debugedit -b "%{_builddir}/.tmp/pip-req-build-"* -d "$PWD"`

4. (Optional: clean `$TMPDIR` manually.)

По сути, это путь, по которому я начал, когда искал интеграцию pip, # 6505 и т. Д.

Итеративные сборки с помощью pip сегодня практически не работают, что является серьезной потерей для групп, которые имеют большой объем кода Python в форме расширения C, поэтому я прибег к вызову сборки с помощью setup.py .

pip нужна команда build а конечный результат команды build должен передаваться другим подкомандам, например wheel , install , так далее.

Прямо сейчас pip эффективно обрабатывает install как build и install , что _не_ то, чего хотят некоторые люди, которые создают и кэшируют двоичные артефакты, устанавливая двоичные файлы поверх чтения -только крепления и т. д.

Я действительно хотел бы, чтобы был способ использовать setup.py для создания двоичных файлов, а затем pip install их, не прибегая к созданию bdist , но сегодня это кажется невозможным , поскольку pip и distutils / setuptools не договариваются о том, где найти двоичные артефакты.

Я действительно хотел бы, чтобы был способ использовать setup.py для создания двоичных файлов, а затем установить их pip, не прибегая к созданию bdist, но сегодня это не представляется возможным, поскольку pip и distutils / setuptools не согласны с где найти бинарные артефакты.

Я не уверен, что понимаю - вы говорите, что хотите использовать двоичные файлы, но не хотите использовать уже существующие двоичные форматы распространения. Это почему?

Я действительно хотел бы, чтобы был способ использовать setup.py для создания двоичных файлов, а затем установить их pip, не прибегая к созданию bdist, но сегодня это не представляется возможным, поскольку pip и distutils / setuptools не согласны с где найти бинарные артефакты.

Я не уверен, что понимаю - вы говорите, что хотите использовать двоичные файлы, но не хотите использовать уже существующие двоичные форматы распространения. Это почему?

Форматы bdist чрезвычайно ограничены. Моя группа должна прибегнуть к тупому формату, например tar, а затем дословно распаковать его (ни один из BSD не поддерживается, Debian не поддерживается и т. Д.).

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

Я также пробовал egg и zip, но им не хватает метаданных, необходимых для установки, используя только file:// URI.

Я возился с попытками встроить сборку с помощью distutils, setuptools в более крупную систему сборки с помощью make, поэтому я не могу сказать, сделал ли я «все правильные вещи», чтобы все работало так, как стандартный bdist вызов бы.

Исходя из https://github.com/pypa/pip/issues/2195#issuecomment -664728481, я могу сказать, что я более чем счастлив переделать # 7882 за --use-feature=in-tree-build .

Ура! Звучит как план!

Давайте также обновим --build этот раз строку документации

Исходя из # 2195 (комментарий), я могу сказать, что я более чем счастлив переделать # 7882 за --use-feature = in-tree-build.

Любопытно, если бы это было разумно не только с помощью командной строки, но и в параметре in-tree-build установленном в pyproject.toml ? Это было бы неплохо для решения # 6276 без необходимости создавать сценарий bash или make-файл для обертывания pip. (Не то чтобы это особенно большая проблема.)

иметь параметр сборки в дереве, установленный в pyproject.toml

@davidhewitt это более или менее вариант 3 в исходном описании проблемы. Насколько я понимаю, в настоящее время консенсус состоит в том, что по возможности лучше избегать дополнительной возможности. Поэтому идея включить древовидную сборку с --use-feature в течение переходного периода с долгосрочной целью сделать его единственным механизмом по умолчанию.

Кстати, я не смогу реализовать это вовремя для 20.3, но я все еще намерен сделать это, надеюсь, в 20.4.

@sbidoul Я написал патч, чтобы помочь внедрить эту функцию - см. # 9091.

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