Chapter 7. 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, whether the project uses setup.py or pyproject.toml, use pyproject RPM macros from the pyproject-rpm-macros package.

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 7.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_pkgversion macro, you set which Python version this package will be built for. To build for the default Python version 3.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 is Pello and, therefore, the name of the Source RPM (SRPM) is python-pello.
  • BuildRequires specifies what packages are required to build and test this package. In BuildRequires, always include python3-devel and other tools that you need to build Python packages. Also list the projects that your software requires, such as python3-setuptools. Add any runtime and testing dependencies that you need to run tests in the %check section.
  • 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 to 3 for the default Python version 3.12 unless you set it to an explicit version, for example, when a later version of Python is available (see footnote 1).
  • The %py3_build and %py3_install macros run the setup.py build and setup.py install commands, respectively, with additional arguments to specify installation locations, the interpreter to use, and other details.

    Note

    Using the setup.py build and setup.py install commands from the setuptools package is deprecated. For modern projects, use the pyproject RPM macros from the pyproject-rpm-macros package. For more information, see Packaging Python projects with pyproject RPM macros.

  • The %check section runs the tests of the packaged project. The exact command depends on the project itself, but you can use the %pytest macro to run the pytest command in an RPM-friendly way.

7.2. Common macros for Python 3 RPMs

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.

Table 7.1. Macros for Python 3 RPMs
MacroNormal DefinitionDescription

%{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 setup.py build command with arguments suitable for an RPM package.

%py3_install

 

Expands to the setup.py install command with arguments suitable for an RPM package.

%{py3_shebang_flags}

sP

The default set of flags for the Python interpreter directives macro, %py3_shebang_fix.

%py3_shebang_fix

 

Changes Python interpreter directives to #! %{python3}, preserves any existing flags (if found), and adds flags defined in the %{py3_shebang_flags} macro.

Enable automatic generation of dependencies for Python RPMs by using upstream-provided metadata.

Prerequisites

Procedure

  1. Include one of the following directories in the resulting RPM:

    • .dist-info
    • .egg-info

      The RPM build process automatically generates virtual pythonX.Ydist provides 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.Ydist virtual provides. Example of a generated requirements tag:

      Requires: python3.12dist(requests)
  2. Inspect the generated Requires.
  3. To remove some of the generated Requires, modify the upstream-provided metadata in the %prep section of the spec file.
  4. To disable the automatic requirements generator, include the %{?python_disable_dependency_generator} macro immediately before the main package’s %description declaration.

Package Python projects that use a pyproject.toml or a setup.py file into RPM packages by using pyproject RPM macros from the CodeReady Linux Builder (CRB) repository.

7.4.1. pyproject RPM macros for Python packaging

Package Python projects into RPM packages by using pyproject RPM macros. These macros work with projects that define metadata in setup.py, pyproject.toml, or both, and invoke a standards-based build backend through a standardized protocol.

Many upstream Python projects no longer rely on a setup.py script. Instead, they store project metadata in pyproject.toml and use a build backend, such as setuptools, flit-core, hatchling, or poetry-core. The pyproject RPM macros invoke any compliant build backend through a standardized protocol instead of calling setup.py directly.

The pyproject RPM macros reuse upstream metadata whenever possible. For example, they can generate BuildRequires from the build-system requirements in pyproject.toml instead of listing the same dependencies manually in the spec file.

The pyproject-rpm-macros package is available in the CodeReady Linux Builder (CRB) repository. The %pyproject_buildrequires macro adds a generated BuildRequires on that package during package builds. CRB content is unsupported by Red Hat. The macros are updated as needed to follow emerging Python packaging standards.

Use pyproject RPM macros to package Python projects, whether the upstream project defines metadata in setup.py, pyproject.toml, or both.

7.4.2. Preparing to use pyproject RPM macros

To package Python projects with pyproject RPM macros, enable the CodeReady Linux Builder (CRB) repository on the build host and configure %pyproject_buildrequires in your RPM spec file.

Important

Red Hat does not support content in the CodeReady Linux Builder repository.

Prerequisites

  • You have root permissions on the build host.
  • The system is registered with Red Hat Subscription Manager.

Procedure

  1. Enable the CodeReady Linux Builder repository on the build host:

    # subscription-manager repos --enable codeready-builder-for-rhel-10-x86_64-rpms
  2. In the RPM spec file, add BuildRequires: python3-devel and use the %pyproject_buildrequires macro in the %generate_buildrequires section:

    BuildRequires: python3-devel
    
    %generate_buildrequires
    %pyproject_buildrequires

In a Python RPM spec file, use pyproject RPM macros to build projects that define metadata in setup.py, pyproject.toml, or both.

You can redefine which Python 3 version the macros use by defining the python3_pkgversion macro at the top of your spec file, for example %global python3_pkgversion 3.14. Omit this macro to build for the default Python 3 version.

Place %pyproject_buildrequires in the %generate_buildrequires section of the spec file. RPM runs the macro in that section to generate build requirements from upstream metadata before the build starts.

Table 7.2. Common pyproject RPM macros for Python 3 RPMs
MacroDescription

%pyproject_buildrequires

Expands build requirements from upstream metadata. Use options such as -g test to include dependencies from a named dependency group.

%pyproject_wheel

Builds a wheel package by using the upstream-specified build backend.

%pyproject_install

Installs the built wheel package into the build root.

%pyproject_save_files

Saves the list of installed files for use in the %files section. Use -l to assert that a license file is found.

%pyproject_check_import

Verifies that the installed package can be imported during the %check section.

%pyproject_files

Expands to the file list saved by %pyproject_save_files. Use it with the -f option in the %files section.

The table lists commonly used macros. For all macros and their options, see the /usr/share/doc/pyproject-rpm-macros/README.md file provided by the pyproject-rpm-macros package.

Use an annotated RPM spec file example to package a Python project that defines metadata in setup.py, pyproject.toml, or both. The example shows pyproject RPM macros for build requirements, wheel builds, installation, and automated file lists.

Example 7.2. An example spec file for a Python library built with pyproject RPM macros

Name:           python-pello
Version:        1.0.2
Release:        1%{?dist}
Summary:        Example Python library

License:        MIT
URL:            https://example.com/Pello
Source:         %{url}/archive/v%{version}/Pello-%{version}.tar.gz

BuildArch:      noarch

%description %_description
Pello is an example package with an executable that prints Hello World! on the command line.

%package -n python3-pello
Summary:        %{summary}

%description -n python3-pello
Pello is an example package with an executable that prints Hello World! on the command line.

%prep
%autosetup -p1 -n Pello-%{version}

%generate_buildrequires
%pyproject_buildrequires

%build
%pyproject_wheel

%install
%pyproject_install

%pyproject_save_files -l pello

%check
%pyproject_check_import
%pytest

%files -n python3-pello -f %{pyproject_files}
  • The %pyproject_buildrequires macro in the %generate_buildrequires section creates build requirements from upstream metadata.
  • The %pyproject_wheel macro builds a wheel package by using the upstream-specified build backend.
  • The %pyproject_install macro installs the wheel into the build root.
  • The %pyproject_save_files -l pello macro records installed files. The -l option verifies that a license file is present. The pello argument lists the importable module named pello.
  • The %check section runs %pyproject_check_import to verify importability and %pytest to run tests.
  • The %files section uses -f %{pyproject_files} to include the file list generated by %pyproject_save_files.

For commonly used macros, see Common pyproject RPM macros for Python 3 RPMs. For all macros and their options, see the /usr/share/doc/pyproject-rpm-macros/README.md file provided by the pyproject-rpm-macros package.

Red Hat logoGithubRedditYoutubeTwitter

Learn

Try, buy, & sell

Communities

About Red Hat

We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.

Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. For more details, see the Red Hat Blog.

About Red Hat Documentation

Legal Notice

Theme

© 2026 Red Hat
Back to top