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 by # macrofile from package python3-pkgversion-macros that is present in 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