Skip to main content
Redhat Developers  Logo
  • AI

    Get started with AI

    • Red Hat AI
      Accelerate the development and deployment of enterprise AI solutions.
    • AI learning hub
      Explore learning materials and tools, organized by task.
    • AI interactive demos
      Click through scenarios with Red Hat AI, including training LLMs and more.
    • AI/ML learning paths
      Expand your OpenShift AI knowledge using these learning resources.
    • AI quickstarts
      Focused AI use cases designed for fast deployment on Red Hat AI platforms.
    • No-cost AI training
      Foundational Red Hat AI training.

    Featured resources

    • OpenShift AI learning
    • Open source AI for developers
    • AI product application development
    • Open source-powered AI/ML for hybrid cloud
    • AI and Node.js cheat sheet

    Red Hat AI Factory with NVIDIA

    • Red Hat AI Factory with NVIDIA is a co-engineered, enterprise-grade AI solution for building, deploying, and managing AI at scale across hybrid cloud environments.
    • Explore the solution
  • Learn

    Self-guided

    • Documentation
      Find answers, get step-by-step guidance, and learn how to use Red Hat products.
    • Learning paths
      Explore curated walkthroughs for common development tasks.
    • Guided learning
      Receive custom learning paths powered by our AI assistant.
    • See all learning

    Hands-on

    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.
    • Interactive labs
      Learn by doing in these hands-on, browser-based experiences.
    • Interactive demos
      Click through product features in these guided tours.

    Browse by topic

    • AI/ML
    • Automation
    • Java
    • Kubernetes
    • Linux
    • See all topics

    Training & certifications

    • Courses and exams
    • Certifications
    • Skills assessments
    • Red Hat Academy
    • Learning subscription
    • Explore training
  • Build

    Get started

    • Red Hat build of Podman Desktop
      A downloadable, local development hub to experiment with our products and builds.
    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.

    Download products

    • Access product downloads to start building and testing right away.
    • Red Hat Enterprise Linux
    • Red Hat AI
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat Developer Toolset

    References

    • E-books
    • Documentation
    • Cheat sheets
    • Architecture center
  • Community

    Get involved

    • Events
    • Live AI events
    • Red Hat Summit
    • Red Hat Accelerators
    • Community discussions

    Follow along

    • Articles & blogs
    • Developer newsletter
    • Videos
    • Github

    Get help

    • Customer service
    • Customer support
    • Regional contacts
    • Find a partner

    Join the Red Hat Developer program

    • Download Red Hat products and project builds, access support documentation, learning content, and more.
    • Explore the benefits

Python packaging for RHEL 9 & 10 using pyproject RPM macros

May 7, 2025
Miro Hrončok
Related topics:
LinuxPython
Related products:
Red Hat Enterprise Linux

    For more than a decade, the setup.py file was the cornerstone of Python packages. When packaging RPM packages for Red Hat Enterprise Linux (RHEL), RPM spec files invoked the setup.py script in %build and %install sections, typically using the %py3_build and %py3_install RPM macros. Every Python project relied on either the standard library's distutils module or the more advanced and widely used setuptools package.

    Python RPM packaging for RHEL 9 and 10 has evolved beyond the traditional setup.py approach. This article explores how the new pyproject RPM macros simplify packaging modern Python projects by supporting diverse build backends and reusing upstream metadata. Whether you're maintaining legacy packages or adopting the latest Python standards, you can use the pyproject RPM macros from the RHEL CRB repository.

    How Python packaging has improved

    Python packaging has undergone a massive overhaul by standardizing a build-system independent format for source trees and storing project metadata in pyproject.toml. The distutils module has been deprecated and removed from the Python standard library. The setup.py script has been deprecated in setuptools. Upstream projects now use various build backends, including flit-core, hatchling, poetry-core, and even the traditional setuptools.

    As a result, it is often not possible to RPM-package upstream Python projects—whether from the Python Package Index (PyPI) or internal package indexes the same way as in RHEL 7 or RHEL 8.

    In Fedora, we created pyproject-rpm-macros, a set of RPM macros designed to package standards-based Python projects into RPM packages. These macros are available in the RHEL 9 and 10 CodeReady Linux Builder (CRB) repository. This allows us to frequently update them to newer versions, often following emerging Python packaging standards—most recently, support for dependency groups in pyproject.toml.

    The pyproject RPM macros are designed with the following principles in mind:

    • Support standards over specific tools.
    • Reuse upstream metadata whenever possible instead of duplicating it in the spec file.

    For example, the old way of RPM-packaging Python invoked setup.py build, which only supported distutils/setuptools-based projects. The pyproject RPM macros instead use a standardized protocol to invoke any standard-compliant Python build backend. This approach remains compatible with traditional projects still using setup.py by falling back to setuptools.

    Another example of metadata reuse is dynamically generating BuildRequires based on upstream metadata instead of listing them manually in the spec file.

    The following is an example spec file.

    Name:           python-example
    Version:        1.2.3
    Release:        1%{?dist}
    Summary:        Example Python library
    License:        MIT
    URL:            https://github.com/fedora-python/example
    Source:         %{url}/archive/v%{version}/example-%{version}.tar.gz
    BuildArch:      noarch
    
    %description %_description
    ...
    
    %package -n python3-example
    Summary:        %{summary}
    
    %description -n python3-example
    ...
    
    %prep
    %autosetup -p1 -n example-%{version}
    
    # Dynamically generates BuildRequires, including:
    # - Build backend dependencies (PEP 518)
    # - Runtime dependencies for tests
    # - Dependencies from a dependency group (PEP 735)
    %generate_buildrequires
    %pyproject_buildrequires -g test
    
    # Build the wheel package using the upstream-specified build backend (PEP 517)
    %build
    %pyproject_wheel
    
    # Install the wheel package and save the file list
    %install
    %pyproject_install
    
    # Explicitly list the installed importable module to avoid accidental installations.
    # Use -l to assert a %%license file is found (PEP 639).
    %pyproject_save_files -l example
    
    # Test importability and run pytest
    # There is no standard yet for running tests
    %check
    %pyproject_check_import
    %pytest
    
    # Use the upstream-generated file list in the %%files section
    %files -n python3-example -f %{pyproject_files}
    
    %changelog
    ...
    

    This approach also works seamlessly with alternate Python versions by setting the following:

    %global python3_pkgversion 3.12

    Next steps

    The new pyproject RPM macros makes packaging modern Python projects easier by supporting diverse build backends and reusing upstream metadata. For more details about the macros, refer to the Fedora Python packaging guidelines or the pyproject-rpm-macros README.

    Related Posts

    • Profiling Python Programs

    • Extracting dependencies from Python packages

    • How to self-host a Python package index using Pulp

    Recent Posts

    • Debugging image mode with Red Hat OpenShift 4.20: A practical guide

    • EvalHub: Because "looks good to me" isn't a benchmark

    • SQL Server HA on RHEL: Meet Pacemaker HA Agent v2 (tech preview)

    • Deploy with confidence: Continuous integration and continuous delivery for agentic AI

    • Every layer counts: Defense in depth for AI agents with Red Hat AI

    What’s up next?

    Learn how large language models (LLMs) are created and use Red Hat Enterprise Linux AI to experiment within an LLM in this hands-on learning path.

    Start the activity
    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Platforms

    • Red Hat AI
    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Build

    • Developer Sandbox
    • Developer tools
    • Interactive tutorials
    • API catalog

    Quicklinks

    • Learning resources
    • E-books
    • Cheat sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site status dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2026 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Chat Support

    Please log in with your Red Hat account to access chat support.