Building PEP 517 python RPMs on Fedora and dealing with python3-opencv

I’m working on packaging one of my projects into an RPM for Fedora. The project uses python hatch for building and I’ve looked at some existing examples in the Fedora tree that use the PEP517 build process. Here is the spec file I came up with:

Name:           mediahug
Version:        0.4.dev4+g155a7b0
Release:        1%{?dist}
Summary:        Video and Media Browser
License:        AGPLv3
URL:            https://battlepenguin.com
Source0:        https://nexus.sumit.im/repository/bp-python-snapshots/packages/%{name}/%{version}/%{name}-%{version}.tar.gz

BuildArch:      noarch
BuildRequires:  python3-devel
BuildRequires:  python3-pytest

# Runtime dependencies
# It appears these are just ignored as the builder pulls them from the
# pyproject.toml file, so I've commented them out
# Requires:       python3dist(rich)
# Requires:       python3dist(pyqt6)
# Requires:       python3dist(rich)
# Requires:       python3dist(opencv)

%description
MediaHug is media and video browser

%prep
%autosetup -p1

%generate_buildrequires
%pyproject_buildrequires

%build
%pyproject_wheel

%install
%pyproject_install
%pyproject_save_files -L %{name}

%check
%pytest

%files -f %{pyproject_files}
%license LICENSE.txt
%doc README.md

%changelog
* Mon Jun 02 2025 Sumit Khanna <sumit@battlepenguin.com> - 0.4.dev4+g155a7b0
- Initial package creation

..and my build Dockerfile is pretty simple:

FROM fedora:42
RUN dnf install rpmdevtools python3-pytest python3-hatch-vcs python3-hatchling python3-devel \
        python3-rich python3-click python3-pyqt6 python3-opencv

Some of the version numbers were a bit too specific, so I recreated the tar with more generic versions (e.g. click>=8 instead of click>=8.1.1) just for testing. (Just in case you pull the tar URL and notice the versions are different).

I get the following when I run rpmbuild -ba mediahug.spec

+ TMPDIR=/root/rpmbuild/BUILD/mediahug-0.4.dev4+g155a7b0-build/mediahug-0.4.dev4+g155a7b0/.pyproject-builddir
+ RPM_TOXENV=py313
+ FEDORA=42
+ HOSTNAME=rpmbuild
+ /usr/bin/python3 -Bs /usr/lib/rpm/redhat/pyproject_buildrequires.py --generate-extras --python3_pkgversion 3 --wheeldir /root/rpmbuild/BUILD/mediahug-0.4.dev4+g155a7b0-build/mediahug-0.4.dev4+g155a7b0/pyproject-wheeldir --output /root/rpmbuild/BUILD/mediahug-0.4.dev4+g155a7b0-build/mediahug-0.4.dev4+g155a7b0-1.fc42.noarch-pyproject-buildrequires
Handling hatchling from build-system.requires
Requirement satisfied: hatchling
   (installed: hatchling 1.27.0)
Handling hatch-vcs from build-system.requires
Requirement satisfied: hatch-vcs
   (installed: hatch-vcs 0.4.0)
Handling click>=8 from hook generated metadata: Requires-Dist (mediahug)
Requirement satisfied: click>=8
   (installed: click 8.1.7)
Handling opencv-python>=4 from hook generated metadata: Requires-Dist (mediahug)
Requirement not satisfied: opencv-python>=4
Handling pyqt6>=6.0.0 from hook generated metadata: Requires-Dist (mediahug)
Requirement satisfied: pyqt6>=6.0.0
   (installed: pyqt6 6.9.0)
Handling python-mpv>=1.0.0 from hook generated metadata: Requires-Dist (mediahug)
Requirement not satisfied: python-mpv>=1.0.0
Handling rich>=13 from hook generated metadata: Requires-Dist (mediahug)
Requirement satisfied: rich>=13
   (installed: rich 13.9.4)
Handling sqlite-connector>=0.1.0 from hook generated metadata: Requires-Dist (mediahug)
Requirement not satisfied: sqlite-connector>=0.1.0
Handling yoyo-migrations>=9.0.0 from hook generated metadata: Requires-Dist (mediahug)
Requirement not satisfied: yoyo-migrations>=9.0.0
+ cat /root/rpmbuild/BUILD/mediahug-0.4.dev4+g155a7b0-build/mediahug-0.4.dev4+g155a7b0-1.fc42.noarch-pyproject-buildrequires
+ rm -rfv mediahug-0.4.dev4+g155a7b0.dist-info/
removed 'mediahug-0.4.dev4+g155a7b0.dist-info/METADATA'
removed directory 'mediahug-0.4.dev4+g155a7b0.dist-info/'
+ RPM_EC=0
++ jobs -p
+ exit 0
error: Failed build dependencies:
	python3dist(opencv-python) >= 4 is needed by mediahug-0.4.dev4+g155a7b0-1.fc42.noarch
	python3dist(python-mpv) >= 1 is needed by mediahug-0.4.dev4+g155a7b0-1.fc42.noarch
	python3dist(sqlite-connector) >= 0.1 is needed by mediahug-0.4.dev4+g155a7b0-1.fc42.noarch
	python3dist(yoyo-migrations) >= 9 is needed by mediahug-0.4.dev4+g155a7b0-1.fc42.noarch
Wrote: /root/rpmbuild/SRPMS/mediahug-0.4.dev4+g155a7b0-1.fc42.buildreqs.nosrc.rpm

I realize python3-mpv python3-sqlite-connector and python3-yoyo-migrations don’t exist in the Fedora repository, so I’ll have to make spec files for those and build them. But I’m wondering about opencv-python. It seems like this package is called python3-opencv on Fedora, but I need to keep opencv-python in the pyproject.toml since that’s the pypi repository package name. Is there a way in the spec file to state that to satisfy opencv-python it can use just python3dist(opencv) instead?

Can you use mock instead of docker to build your rpm?
Mock is the tool used by Fedora for this purpose.

In the case where sources file need a small change I add a patch to the rpm to male the small change. In this case changing the name in the pyproject.

I was sure we require Python packages to “provide” by PyPi-name, but I can’t find it in the guidelines. I still think it would be helpful if python3-opencv would provide python3dist(opencv-python).

Until then, rewriting pyproject.toml in the spec file with a quick sed -i-command (as suggested by @barryascott ) is the standard procedure because it still allows the pyproject macros to do their thing. That’s also how you could rewrite overly tight version requirements.

1 Like

I believe we require the python3- prefix on the RPM by policy.

But that should not change what is actually installed into python’s site-packages which should be the same names as you would get by installing from PyPI.

Also note that PyPI package names do not need to match the folder that the contents installs into either.

Sure.

This is all about the provides that the package specifies:

# rpm -q --provides python3-Traits
python-Traits = 6.4.3-5.fc42
python-traits = 6.4.3-5.fc42
python3-Traits = 6.4.3-5.fc42
python3-Traits(x86-64) = 6.4.3-5.fc42
python3-traits = 6.4.3-5.fc42
python3.13-Traits = 6.4.3-5.fc42
python3.13-traits = 6.4.3-5.fc42
python3.13dist(traits) = 6.4.3
python3dist(traits) = 6.4.3

ah interesting. My CI server doesn’t run an rpm based distribution and the pipelines are all in Docker, but I’ll put this on the to-do list. That could be very helpful in making packages for other rpm-based distros. Thanks!

For my spec file, I patched the pyproject.toml in the %prep section and that seems to take care of the opencv and mpv python package.

%prep
%autosetup -p1
sed -i s/opencv-python/opencv/g pyproject.toml
sed -i s/python-mpv/mpv/g pyproject.toml

I’m now working on building some of the dependencies that don’t have rpms/spec files. With python-mpv. I created the following for python-mpv and it seems to test, build and install correctly:

Name:           python3-mpv
Version:        1.0.8
Release:        1%{?dist}
Summary:        Python interface to the mpv media player
License:        GPLv2,LGPLv2.1
URL:            https://github.com/jaseg/python-mpv
Source0:        https://github.com/jaseg/python-mpv/archive/v%{version}.tar.gz
BuildArch:      noarch
BuildRequires:  python3-devel
BuildRequires:  python3-setuptools
BuildRequires:  mpv-devel
BuildRequires:  python3-pyvirtualdisplay
Requires:       mpv

%description
python-mpv is a ctypes-based python interface to the mpv media player.
It gives you more or less full control of all features of the player,
just as the lua interface does.

%prep
%autosetup -p1 -n python-mpv-%{version}

%generate_buildrequires
%pyproject_buildrequires

%build
%pyproject_wheel

%install
%pyproject_install
%pyproject_save_files -L mpv

%check
%pytest

%files -f %{pyproject_files}
%license LICENSE.GPL
%license LICENSE.LGPL
%doc README.rst

%changelog
* Thu Jun 26 2025 Sumit Khanna <sumit@penguindreams.org> - 1.0.8-1
- Created python-mpv package as dependency for mediahug

I ran rpm -Uvh /root/rpmbuild/RPMS/noarch/python3-mpv-1.0.8-1.fc42.noarch.rpm, and checked the installed package with rpm -ql python3-mpv and by importing it in a python shell.

Going to work on the other two dependencies, but just wanted to make sure my spec for python-mpv follows best practices. Let me know if anything looks wrong and thanks for the help!