Python 3 applications and modules in EPEL 7+
Since Python minor version are not ABI compatible and because EPEL guidelines strongly discourage breaking ABI compatibility, separate Python 3 minor versions in EPEL 7+ are packaged as separate python3X (currently Python34) packages. At any given time one python3X package is considered "the default". This necessitates some changes to spec files:
All Packages
- All references to python3 (except in macro names) need to be replaced with python%{python3_pkgversion}.
- make sure that all hashbangs in resulting package are in form "#!/usr/bin/python3.X". Macros %{__python3} and %{__python3_other} in EPEL have these values, so if you invoke %{__python3} setup.py <action>, the entry points will automatically be set correctly. You must replace any upstream hardcoded hashbangs during build by using sed or other means.
Modules
- where in Fedora, a module has python3-foo subpackage, in EPEL the subpackage must be python%{python3_pkgversion}-foo.
- Add definition and %prep, %build and %install (and %check) steps of python%{python3_other_pkgversion}-X subpackage. which looks exactly the same as python%{python3_pkgversion}-X subpackage, it just uses different macros; build of this subpackage has to be conditionalized by the %with_python3_other macro, which is defined in the minimal buildroot.
- scripts/entry-points (if any) in %{_bindir} should be split like this among subpackages:
- python-X subpackage should own %{_bindir}/foo and possibly %{_bindir}/foo-2 and %{_bindir}/foo-2.7 files
- python%{python3_pkgversion}-X should own %{_bindir}/foo-3 and %{_bindir}/foo-%{python3_version} files
- python%{python3_other_pkgversion}-X should own just %{_bindir}/foo-%{python3_other_version}
- Note: often, upstreams implement their own entrypoint versioning and there are several different schemes they use: "foo-3.X", "foo-3X", "foo3.X", "foo3X". If upstream has any of these, it is advisable to adopt it. Packager should only manually create versioned files when they don't exist.
Example Spec
# note: macros %%python3_pkgversion, %%python3_other_pkgversion and %%with_python3_other are defined
# in the minimal buildroot; %%python3_pkgversion is also available in Fedora, so it's possible to have a common
# specfile for EPEL and Fedora
%global srcname example
%global sum An example python module
Name: python-%{srcname}
Version: 1.2.3
Release: 1%{?dist}
Summary: %{sum}
License: MIT
URL: http://http://pypi.python.org/pypi/%{srcname}
Source0: http://pypi.python.org/packages/source/e/%{srcname}/%{srcname}-%{version}.tar.gz
BuildArch: noarch
BuildRequires: python2-devel
BuildRequires: python%{python3_pkgversion}-devel
%if 0%{?with_python3_other}
BuildRequires: python%{python3_other_pkgversion}-devel
%endif
%description
An python module which provides a convenient example.
%package -n python2-%{srcname}
Summary: %{sum}
%{?python_provide:%python_provide python2-%{srcname}}
%description -n python2-%{srcname}
An python module which provides a convenient example.
%package -n python%{python3_pkgversion}-%{srcname}
Summary: %{sum}
BuildRequires: python%{python3_pkgversion}-othermodule
Requires: python%{python3_pkgversion}-othermodule
%{?python_provide:%python_provide python%{python3_pkgversion}-%{srcname}}
%description -n python%{python3_pkgversion}-%{srcname}
python%{python3_pkgversion} build of X.
%endif
%if 0%{?with_python3_other}
%package -n python%{python3_other_pkgversion}-%{srcname}
Summary: python%{python3_other_pkgversion} build of X
BuildRequires: python%{python3_other_pkgversion}-othermodule
Requilres: python%{python3_other_pkgversion}-othermodule
%{?python_provide:%python_provide python%{python3_other_pkgversion}-%{srcname}}
%description -n python%{python3_other_pkgversion}-%{srcname}
python%{python3_other_pkgversion} build of X.
%endif
%prep
%autosetup
%build
%py2_build
%py3_build
%py3_other_build
%install
# Must do the python3_other install first, then python3 and then python2.
# The scripts in /usr/bin are overwritten with every setup.py install.
%py3_other_install
%py3_install
%py2_install
%check
%{__python2} setup.py test
%{__python3} setup.py test
%{__python3_other} setup.py test
# Note that there is no %%files section for the unversioned python module if we are building for several python runtimes
%files -n python2-%{srcname}
%license COPYING
%doc README.rst
%{python2_sitelib}/*
%{_bindir}/sample-exec-%{python2_version}
%files -n python%{python3_pkgversion}-%{srcname}
%license COPYING
%doc README.rst
%{python3_sitelib}/*
%{_bindir}/sample-exec
%{_bindir}/sample-exec-%{python3_version}
%if 0%{?with_python3_other}
%files -n python%{python3_other_pkgversion}-%{srcname}
%license COPYING
%doc README.rst
%{python3_other_sitelib}/*
%{_bindir}/sample-exec
%{_bindir}/sample-exec-%{python3_other_version}
%endif
%changelog
Using %py_package macro
You can use the %python_package macro to generate the needed sub-package declarations automatically. One caveat is that all python dependencies must have python2/python3-foo provides. While this is mandated by this spec, not all python packages have been brought up to date. All BuildRequires/Requires/Provides must be declared inside the header macro, along with the summary. %python_provide is automatically called so no need to use it.
%global srcname example
%global sum An example python module
Name: python-%{srcname}
Version: 1.2.3
Release: 1%{?dist}
Summary: %{sum}
License: MIT
URL: http://pypi.python.org/pypi/%{srcname}
Source0: http://pypi.python.org/packages/source/e/%{srcname}/%{srcname}-%{version}.tar.gz
BuildArch: noarch
%global pkgdesc \
A description of the package \
over several lines.
%global header \
Summary: %{sum} \
BuildRequires: python-devel \
BuildRequires: python-foo \
Requires: python-foo
%py_package %{srcname} %{header} %{pkgdesc}
%prep
%autosetup
%build
%py2_build
%py3_build
%py3_other_build
%install
# Must do the python3_other install first, then python3 and then python2.
# The scripts in /usr/bin are overwritten with every setup.py install.
%py3_other_install
%py3_install
%py2_install
%check
%{__python2} setup.py test
%{__python3} setup.py test
%{__python3_other} setup.py test
# Note that there is no %%files section for the unversioned python module if we are building for several python runtimes
%files -n python2-%{srcname}
%license COPYING
%doc README.rst
%{python2_sitelib}/*
%{_bindir}/sample-exec-%{python2_version}
%files -n python%{python3_pkgversion}-%{srcname}
%license COPYING
%doc README.rst
%{python3_sitelib}/*
%{_bindir}/sample-exec
%{_bindir}/sample-exec-%{python3_version}
%if 0%{?with_python3_other}
%files -n python%{python3_other_pkgversion}-%{srcname}
%license COPYING
%doc README.rst
%{python3_other_sitelib}/*
%{_bindir}/sample-exec
%{_bindir}/sample-exec-%{python3_other_version}
%endif
%changelog
Using %py3_package macro
For python packages that already have python2 packages in RHEL, the EPEL package must only build the python3 versions of the module. You can use the %py3_package macro to generate the needed python3 sub-package declarations automatically as above.
%global srcname example
%global sum An example python module
Name: python3-%{srcname}
Version: 1.2.3
Release: 1%{?dist}
Summary: %{sum}
License: MIT
URL: http://pypi.python.org/pypi/%{srcname}
Source0: http://pypi.python.org/packages/source/e/%{srcname}/%{srcname}-%{version}.tar.gz
BuildArch: noarch
%global pkgdesc \
A description of the package \
over several lines.
%global header \
Summary: %{sum} \
BuildRequires: python-devel \
BuildRequires: python-foo \
Requires: python-foo
%py3_package %{srcname} %{header} %{pkgdesc}
%prep
%autosetup
%build
%py3_build
%py3_other_build
%install
# Must do the python3_other install first, then python3 and then python2.
# The scripts in /usr/bin are overwritten with every setup.py install.
%py3_other_install
%py3_install
%check
%{__python3} setup.py test
%{__python3_other} setup.py test
# Note that there is no %%files section for the unversioned python module
%files -n python%{python3_pkgversion}-%{srcname}
%license COPYING
%doc README.rst
%{python3_sitelib}/*
%{_bindir}/sample-exec
%{_bindir}/sample-exec-%{python3_version}
%if 0%{?with_python3_other}
%files -n python%{python3_other_pkgversion}-%{srcname}
%license COPYING
%doc README.rst
%{python3_other_sitelib}/*
%{_bindir}/sample-exec
%{_bindir}/sample-exec-%{python3_other_version}
%endif
%changelog
