CLR – Cross – Eclipse – Free Pascal – GNOME – Go – Haskell – Java – KDE – Kernel – Lisp – MinGW – Nonfree – OCaml – Perl – PHP – Python – Ruby – VCS – Web – Wine
Этот документ охватывает стандарты и рекомендации по написанию PKGBUILDов для программного обеспечения Python.
Именование пакета
Для библиотечных модулей Python 3 используйте python-modulename
. Также используйте префикс, если пакет предоставляет программу, тесно связанную с экосистемой Python (например, pip или tox). Для других приложений используйте только имя программы.
Архитектура
Смотрите PKGBUILD#arch.
Пакет Python, содержащий расширения C, является архитектурно-зависимым. В противном случае он, скорее всего, является архитектурно-независимым.
Пакеты, собранные с помощью setuptools, определяют свои расширения C с помощью ключевого слова ext_modules
в setup.py
.
Исходники
URL загрузки, связанные с сайтом PyPI, содержат непредсказуемый хэш, который необходимо получать с сайта PyPI каждый раз, когда пакет должен быть обновлен. Это делает их непригодными для использования в PKGBUILD. PyPI предоставляет альтернативную стабильную схему: массив source=()
PKGBUILD#source должен использовать следующие шаблоны URL:
- Исходный пакет
https://files.pythonhosted.org/packages/source/${_name::1}/$_name/$_name-$pkgver.tar.gz
- рулевой пакет Pure Python
-
https://files.pythonhosted.org/packages/py2.py3/${_name::1}/$_name/${_name//-/_}-$pkgver-py2.py3-none-any.whl
(Bilingual – Python 2 and Python 3 compatible) -
https://files.pythonhosted.org/packages/py3/${_name::1}/$_name/${_name//-/_}-$pkgver-py3-none-any.whl
(Python 3 only) - Обратите внимание, что имя дистрибутива может содержать тире, а его представление в имени файла 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 packages are generally installed using language-specific package manager such as pip, which fetches packages from an online repository (usually PyPI, the Python Package Index) and tracks the relevant files.
However, for managing Python packages from within PKGBUILD
s, one needs to "install" the Python package to the temporary location $pkgdir/usr/lib/python<Python version>/site-packages/$pkgname
.
For Python packages using standard metadata to specify their build backend in pyproject.toml
, this can most easily achieved using python-build and python-installer.
Old packages might fail to specify that they use setuptools, and only offer a setup.py
that has to be invoked manually.
depends
array otherwise they will not be installed.Основные стандарты (PEP 517)
Рабочий процесс, основанный на стандартах, прост: Создайте колесо с помощью 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
results in only a wheel file to be built, no source distribution. -
--no-isolation
means that the package is built using what is installed on your system (which includes packages you specified independs
), by default the tool creates an isolated virtual environment and performs the build there. -
--destdir="$pkgdir"
prevents trying to directly install in the host system instead of inside the package file, which would result in a permission error -
--compile-bytecode=...
or--no-compile-bytecode
can be passed toinstaller
, but the default is sensibly picked, so this should not be necessary.
build
and putting the .whl
file in your source
array is discouraged in favor of building from source, and should only be used when the latter is not a viable option (for example, packages which only come with wheel sources, and therefore cannot be built from source).python-…-git
), include the command git -C "${srcdir}/${pkgname}" clean -dfx
in your prepare
function. This removes stale wheels along with other build artifacts, and helps prevent issues further down the road. See also upstream issues for setuptools and 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()
, если это имеет место.
Если полученный пакет включает исполняемые файлы, которые импортируют устаревший модуль pkg_resources, то setuptools должен быть дополнительно указан как depends
в функции разделения package_*()
; альтернативно, если PKGBUILD устанавливает пакет Python только для одной версии Python, setuptools должен быть перемещен из makedepends
в depends
.
Некоторые пакеты пытаются использовать 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
для запуска testsuites, поскольку она явно предназначена для проверки повторяющихся конфигураций, загруженных из 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" # For nosetests python setup.py nosetests # For pytest - needs python-pytest-runner python setup.py pytest }
Советы и рекомендации
Обнаружение удаленных подписей PGP на PyPI
Если для данного тарбола Python 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-пакета верхнего уровня. Если вы столкнулись с этим, то можете помочь, подав заявку в проект пакета с просьбой исправить это, например, вот так.