Chapter 2. Packaging Python 3 RPMs
You can install Python packages on your system by using the DNF package manager. DNF uses the RPM package format, which offers more downstream control over the software.
Packaging a Python project into an RPM package provides the following advantages compared to native Python packages:
- Dependencies on Python and non-Python packages are possible and strictly enforced by the DNF package manager.
- You can cryptographically sign the packages. With cryptographic signing, you can verify, integrate, and test contents of RPM packages with the rest of the operating system.
- You can run tests during the build process.
The packaging format of native Python packages follows the specifications published by the Python Packaging Authority (PyPA). Historically, most Python projects used the distutils or setuptools utilities for packaging and defined package information in the setup.py file. However, options for creating native Python packages have evolved over time:
-
To package Python software that uses the
setup.pyfile, follow this document. -
To package more modern packages with
pyproject.tomlfiles, read theREADMEfile in thepyproject-rpm-macrossources. Thepyproject-rpm-macrospackage is in the CodeReady Linux Builder (CRB) repository. That repository contains unsupported packages. Thepyproject-rpm-macroscontent changes as needed to support newer Python packaging standards. For links to the PyPA specifications and thepyproject-rpm-macrosrepository, see Additional resources.
2.1. A spec file description for an example Python package Copy linkLink copied to clipboard!
Review the notes about Python RPM spec file specifics in the following example of the python3-pello package.
The RPM spec file for Python projects has some specifics compared to non-Python RPM spec files. For example, it is recommended for any RPM package name of a Python library to include the python3- prefix.
Example 2.1. An example SPEC file for the program written in Python
%global python3_pkgversion 3
Name: python-pello
Version: 1.0.2
Release: 1%{?dist}
Summary: Example Python library
License: MIT
URL: https://github.com/fedora-python/Pello
Source: %{url}/archive/v%{version}/Pello-%{version}.tar.gz
BuildArch: noarch
BuildRequires: python%{python3_pkgversion}-devel
# Build dependencies need to be specified manually
BuildRequires: python%{python3_pkgversion}-setuptools
# Test dependencies need to be specified manually
# Runtime dependencies need to be BuildRequired manually to run tests during build
BuildRequires: python%{python3_pkgversion}-pytest >= 3
%global _description %{expand:
Pello is an example package with an executable that prints Hello World! on the command line.}
%description %_description
%package -n python%{python3_pkgversion}-pello
Summary: %{summary}
%description -n python%{python3_pkgversion}-pello %_description
%prep
%autosetup -p1 -n Pello-%{version}
%build
# The macro only supports projects with setup.py
%py3_build
%install
# The macro only supports projects with setup.py
%py3_install
%check
%pytest
# Note that there is no %%files section for python-pello
%files -n python%{python3_pkgversion}-pello
%doc README.md
%license LICENSE.txt
%{_bindir}/pello_greeting
# The library files needed to be listed manually
%{python3_sitelib}/pello/
# The metadata files needed to be listed manually
%{python3_sitelib}/Pello-*.egg-info/
-
By defining the
python3_pkgversionmacro, you set which Python version this package will be built for. To build for the default Python version3.12, remove the line. -
When packaging a Python project into RPM, always add the
python-prefix to the original name of the project. The project name here isPelloand, therefore, the name of the Source RPM (SRPM) ispython-pello. -
BuildRequiresspecifies what packages are required to build and test this package. InBuildRequires, always includepython3-develand other tools that you need to build Python packages. Also list the projects that your software requires, such aspython3-setuptools. Add any runtime and testing dependencies that you need to run tests in the%checksection. -
When choosing a name for the binary RPM (the package that users will be able to install), add a versioned Python prefix. Use the
python3-prefix for the default Python 3.12. You can use the%{python3_pkgversion}macro, which evaluates to3for the default Python version3.12unless you set it to an explicit version, for example, when a later version of Python is available (see footnote 1). The
%py3_buildand%py3_installmacros run thesetup.py buildandsetup.py installcommands, respectively, with additional arguments to specify installation locations, the interpreter to use, and other details.NoteUsing the
setup.py buildandsetup.py installcommands from thesetuptoolspackage is deprecated. Support for these commands is not guaranteed in later major Red Hat Enterprise Linux releases. You can use pyproject-rpm-macros instead.-
The
%checksection runs the tests of the packaged project. The exact command depends on the project itself, but you can use the%pytestmacro to run thepytestcommand in an RPM-friendly way.
2.2. Common macros for Python 3 RPMs Copy linkLink copied to clipboard!
In a Python RPM spec file, always use the macros for Python 3 RPMs rather than hardcoding their values.
You can redefine which Python 3 version is used in these macros. To do so, define the python3_pkgversion macro at the top of your spec file. For more information, see A spec file description for an example Python package. If you define the python3_pkgversion macro, the macro values in the following table match that Python 3 version.
| Macro | Normal Definition | Description |
|---|---|---|
| %{python3_pkgversion} | 3 | The Python version that is used by all other macros. Redefine this macro when you build for a different Python version than the default. |
| %{python3} | /usr/bin/python3 | The Python 3 interpreter. |
| %{python3_version} | 3.12 | The major.minor version of the Python 3 interpreter. |
| %{python3_sitelib} | /usr/lib/python3.12/site-packages | The location where pure-Python modules are installed. |
| %{python3_sitearch} | /usr/lib64/python3.12/site-packages | The location where modules containing architecture-specific extension modules are installed. |
| %py3_build |
Expands to the | |
| %py3_install |
Expands to the | |
| %{py3_shebang_flags} | sP |
The default set of flags for the Python interpreter directives macro, |
| %py3_shebang_fix |
Changes Python interpreter directives to |
2.3. Using automatically generated dependencies for Python RPMs Copy linkLink copied to clipboard!
Enable automatic generation of dependencies for Python RPMs by using upstream-provided metadata.
Prerequisites
-
A
specfile for the RPM exists. For more information, see A spec file description for an example Python package.
Procedure
Include one of the following directories in the resulting RPM:
-
.dist-info .egg-infoThe RPM build process automatically generates virtual
pythonX.Ydistprovides from these directories, for example:python3.12dist(pello)The Python dependency generator then reads the upstream metadata and generates runtime requirements for each RPM package using the generated
pythonX.Ydistvirtual provides. Example of a generated requirements tag:Requires: python3.12dist(requests)
-
-
Inspect the generated
Requires. -
To remove some of the generated
Requires, modify the upstream-provided metadata in the%prepsection of thespecfile. -
To disable the automatic requirements generator, include the
%{?python_disable_dependency_generator}macro immediately before the main package’s%descriptiondeclaration.