From Fedora Project Wiki

Python 3 applications and modules in EPEL 7+

The why's
Please refer to User:Bkabrda/EPEL7_Python3 for more detailed information.

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