Jump to content

Python package guidelines (Русский)

From ArchWiki
Состояние перевода: На этой странице представлен перевод статьи Python package guidelines. Дата последней синхронизации: 6 декабря 2023. Вы можете помочь синхронизировать перевод, если в английской версии произошли изменения.
Указания по созданию пакетов

32-bitCLRCMakeCrossDKMSEclipseElectronFontFree PascalGNOMEGoHaskellJavaKDEKernelLispMesonMinGWNode.jsNonfreeOCamlPerlPHPPythonRRubyRustShellVCSWebWine

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

Именование пакета

Для библиотек Python 3 используйте python-имямодуля. Также используйте префикс, если пакет предоставляет программу, тесно связанную с экосистемой Python (например, pip или tox). Для других приложений используйте только имя программы.

Примечание Название пакета должно быть полностью в нижнем регистре.

Архитектура

Смотрите PKGBUILD (Русский)#arch.

Пакет Python, содержащий расширения C, является архитектурно-зависимым. В противном случае он, скорее всего, является архитектурно-независимым.

Пакеты, собираемые с помощью setuptools, определяют свои расширения C с помощью ключевого слова ext_modules в setup.py.

Исходники

Примечание Согласно RFC0020, исходники стоит по возможности получать непосредственно у апстрима, а не из sdist-архивов на PyPI.

URL загрузки, связанные с сайтом PyPI, содержат непредсказуемый хэш, который необходимо получать с сайта PyPI каждый раз, когда пакет должен быть обновлён. Это делает их непригодными для использования в PKGBUILD. PyPI предоставляет альтернативную стабильную схему: массив source должен использовать следующие шаблоны URL:

Архив с исходным кодом
https://files.pythonhosted.org/packages/source/${_name::1}/$_name/$_name-$pkgver.tar.gz
Пакет wheel, содержащий только Python-код
https://files.pythonhosted.org/packages/py2.py3/${_name::1}/$_name/${_name//-/_}-$pkgver-py2.py3-none-any.whl (для пакета, совместимого с Python 2 и Python 3)
https://files.pythonhosted.org/packages/py3/${_name::1}/$_name/${_name//-/_}-$pkgver-py3-none-any.whl (для пакета, совместимого только с Python 3)
Обратите внимание, что имя дистрибутива может содержать тире, а его представление в имени файла wheel — нет (они преобразуются в символы подчёркивания).
Архитектурно-зависимый пакет wheel
Дополнительные массивы, специфичные для архитектуры, могут быть добавлены путём добавления подчёркивания и имени архитектуры, например, source_x86_64=('...'). Также можно использовать _py=cp310, чтобы не повторять версию Python:
https://files.pythonhosted.org/packages/$_py/${_name::1}/$_name/${_name//-/_}-$pkgver-$_py-${_py}m-manylinux1_x86_64.whl

Обратите внимание, что используется переменная _name вместо pkgname, поскольку пакеты Python обычно имеют префикс python-. Эта переменная может быть определена следующим образом:

_name=${pkgname#python-} 

Методы установки

Пакеты Python обычно устанавливаются с помощью специального менеджера пакетов, такого как pip, который получает пакеты из онлайн-репозитория (обычно PyPI, Python Package Index) и отслеживает соответствующие файлы.

Однако для управления пакетами Python из PKGBUILD необходимо «установить» пакет Python во временное место $pkgdir/usr/lib/python<версия Python>/site-packages/$pkgname.

Для пакетов Python, использующих стандартные метаданные для указания бэкенда сборки в файле pyproject.toml, это проще всего сделать с помощью python-build и python-installer. Старые пакеты могут не указывать, что они используют setuptools, и предлагать только setup.py, который должен быть вызван вручную.

Примечание Зависимости, прописанные в метаданных, должны быть добавлены в массив depends, иначе они не будут установлены.

Основанный на стандартах (PEP 517)

Совет Если сборка производится из исходников апстрима, а апстрим полагается на git для получения строки версии проекта, перед сборкой wheel-пакета необходимо задать значение $pkgver переменным окружения, специфичным для используемого инструментария:

Рабочий процесс, основанный на стандартах, прост: создайте wheel-пакет с помощью python-build и установите его в $pkgdir с помощью python-installer:

makedepends=(python-build python-installer python-wheel) build() { cd "$_name-$pkgver" python -m build --wheel --no-isolation } package() { cd "$_name-$pkgver" python -m installer --destdir="$pkgdir" dist/*.whl }

где

  • --wheel указывает создать только wheel-пакет, без архива с исходным кодом.
  • --no-isolation указывает, что пакет должен быть собран с использованием установленных в системе зависимостей (включая пакеты, указанные вами в depends); по умолчанию без этой опции для сборки создаётся изолированное виртуальное окружение.
  • --destdir="$pkgdir" предотвращает попытку прямой установки в хост-систему, а не внутрь файла пакета, что привело бы к ошибке доступа
  • --compile-bytecode=... или --no-compile-bytecode можно передать в installer, но значение по умолчанию выбрано разумно, поэтому в этом нет необходимости.
Важно Пропуск build и помещение файла .whl в массив source не рекомендуется и должно использоваться только в тех случаях, когда сборка из исходников невозможна (например, для программ, которые поставляются только в виде wheel-пакетов и потому не могут быть собраны из исходных текстов).
Важно Если ваш пакет является VCS-пакетом (python-…-git), добавьте в функцию prepare команду git -C "${srcdir}/${pkgname}" clean -dfx. Это удалит устаревшие wheel-пакеты вместе с другими артефактами сборки и поможет избежать проблем в дальнейшем. Смотрите также issues в setuptools и Poetry.

setuptools или distutils

Если pyproject.toml отсутствует или не содержит таблицу [build-system], это означает, что проект использует старый формат, использующий файл setup.py, который вызывает setuptools или distutils. Обратите внимание, что хотя distutils включен в стандартную библиотеку Python, наличие установленного setuptools означает, что вы используете пропатченную версию distutils.

makedepends=('python-setuptools') # если только он не требует именно distutils build() { cd "$_name-$pkgver" python setup.py build } package() { cd "$_name-$pkgver" python setup.py install --root="$pkgdir" --optimize=1 }

где:

  • --root="$pkgdir" работает как --destdir выше
  • --optimize=1 заранее компилирует оптимизированные файлы байткода (.opt-1.pyc), чтобы их мог отслеживать pacman, вместо ленивого их создания при запуске программы.
  • Добавление --skip-build оптимизирует ненужную попытку повторного выполнения шагов сборки, уже запущенных в функции build(), если это имеет место.

Некоторые пакеты пытаются использовать setuptools и возвращаются к distutils, если setuptools не может быть импортирован. В этом случае setuptools должен быть добавлен как makedepends, чтобы результирующие метаданные Python были лучше.

Если пакет требует сборки setuptools из-за включения исполняемых файлов (что не поддерживается distutils), но импортирует только distutils, то при сборке будет выдано предупреждение, а полученный пакет будет повреждён (он не будет содержать исполняемых файлов):

/usr/lib/python3.8/distutils/dist.py:274: UserWarning: Unknown distribution option: 'entry_points' warnings.warn(msg)

Необходимо сообщить об ошибке в upstream. Для обхода проблемы можно использовать недокументированную функцию setuptools:

# не работает из-за distutils python setup.py build # работает, используя setuptools shim python -m setuptools.launch setup.py build

Если пакет использует python-setuptools-scm, пакет, скорее всего, не будет собран с ошибкой, такой как:

LookupError: setuptools-scm was unable to detect version for /build/python-jsonschema/src/jsonschema-3.2.0. Make sure you're either building from a fully intact git repository or PyPI tarballs. Most other sources (such as GitHub's tarballs, a git checkout without the .git folder) don't contain the necessary metadata and will not work.

Чтобы пакет собрался, нужно экспортировать переменную окружения SETUPTOOLS_SCM_PRETEND_VERSION со значением $pkgver:

export SETUPTOOLS_SCM_PRETEND_VERSION=$pkgver 

Проверка

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

Большинство проектов Python, предоставляющих набор тестов, используют nosetests или pytest для запуска тестов с test в имени файла или каталога, содержащего набор тестов. В общем случае для запуска набора тестов достаточно просто запустить nosetests или pytest.

check(){ cd "$srcdir/foo-$pkgver" # Для nosetests nosetests # Для pytest pytest } 

Если есть скомпилированное расширение C, тесты необходимо запускать, используя $PYTHONPATH, отражающий текущую мажорную и минорную версию Python, чтобы найти и загрузить его.

check(){ cd "$pkgname-$pkgver" local python_version=$(python -c 'import sys; print("".join(map(str, sys.version_info[:2])))') # Для nosetests PYTHONPATH="$PWD/build/lib.linux-$CARCH-cpython-${python_version}" nosetests # Для pytest PYTHONPATH="$PWD/build/lib.linux-$CARCH-cpython-${python_version}" pytest }

Некоторые проекты предоставляют setup.py точки входа для запуска теста. Это работает как для pytest, так и для nosetests.

check(){ cd "$srcdir/foo-$pkgver" # Для nosetests python setup.py nosetests # Для pytest - нужен python-pytest-runner python setup.py pytest } 

Советы и рекомендации

Обнаружение отдельных подписей PGP на PyPI

Важно В мае 2023 функция предоставления отдельных подписей OpenPGP на PyPI была удалена.

Если для sdist-архива существуют отдельные PGP-подписи — их следует использовать для проверки архива. Однако файлы подписей не отображаются непосредственно в разделе загрузки файлов какого-либо проекта на pypi.org. Чтобы обнаружить sdist и их потенциальные файлы подписей, можно воспользоваться этим сервисом для получения обзора по каждому проекту: https://pypi.debian.net/.

Для python-requests это будет https://pypi.debian.net/requests.

Использование версии python

Иногда во время подготовки, сборки, тестирования или установки требуется указать мажорную и минорную версию Python для системы. Не записывайте это жёстко в коде (например, 3.9 или 3.10), а запустите интерпретатор Python для получения информации и сохранения её в локальной переменной:

check(){ local python_version=$(python -c 'import sys; print(".".join(map(str, sys.version_info[:2])))') ... }

Использование site-packages

Иногда во время сборки, тестирования или установки требуется обратиться к системному каталогу site-packages. Не следует записывать путь жёстко в коде, вместо этого запустите интерпретатор Python для получения пути и сохранения его в локальной переменной:

check(){ local site_packages=$(python -c "import site; print(site.getsitepackages()[0])") ... }

Тестовый каталог в site-packages

Убедитесь, что вы не установили каталог с именем tests в site-packages. (т.е. /usr/lib/pythonX.Y/site-packages/tests/). Некоторые Python-проекты, использующие setuptools, иногда неправильно настроены и добавляют каталог с тестами в качестве Python-пакета верхнего уровня. Если вы столкнулись с этим, то можете помочь, отправив проекту сообщение об ошибке с просьбой исправить это, например, вот так.