From Mageia wiki
Jump to: navigation, search

Rules

Naming Conventions

These naming guidelines only apply to Python packages whose main purpose is providing a Python library; packages that mainly provide user-level tools that happen to be written in Python do not need to follow these naming guidelines.

  • The name of a Python extension/library package must be of the form python-UPSTREAM. If the upstream name UPSTREAM contains "python", that should be dropped from the name. The UPSTREAM name should be lowercased with all runs of the characters ., -, or _ replaced with a single - character according to PEP 503. python-UPSTREAM is also the name of the directory in svn.
  • Packages for Python 3 must be of the form python3-UPSTREAM. This is done by defining a subpackage with this name.

Rationale:

  • Using a prefix is serving as a name space, and clearly shows how to find Python modules.
  • Having everything in normalized and lower case is easier to read, and offers a consistent sorting.

pyc/pyo Policy

Files should be compiled before rpm creation and includes. If you do not include them in your packages, Python will try to create them when the user runs the program. If the system administrator uses them, then the files will be successfully written. Later, when the package is removed, the .pyc and .pyo files will be left behind on the filesystem. To prevent that you need to byte compile the files when building your package and include the files in the %files section.

As often .pyo files are exactly the same as .pyc, the Mageia build system has brp-python-hardlink enabled. This will hardlink these files together (like fdupes does).

Files to Include

When installing Python modules we include several different types of files.

  • *.py source files because they are used when generating tracebacks
  • *.pyc and *.pyo byte compiled files
  • *.egg-info files or directories. If these are generated by the module's build scripts they must be included in the package because they might be needed by other applications and modules at run-time.

Building for Several Versions of Python

As of Mageia 8, only Python 3 is supported. Python 2 packages should no longer be created since there is no Python 2 interpreter with which to run them.

Compile to Byte Code

If Python code is installed into a nonstandard location, it might need to be compiled manually. The %py_byte_compile macro takes two arguments. The first is the Python interpreter to use for byte compiling. The second is a file or directory to byte compile. If the second argument is a directory, the macro will recursively byte compile any *.py file in the directory.

No %{} for py_byte_compile: RPM macros can only take arguments when they do not have curly braces around them. Therefore, py_byte_compile won't work correctly if you write: %{py_byte_compile} %{__python}}

Writing the spec-File

Tags

Group should be Development/Python:

 Group: Development/Python

For pure Python packages, BuildArch must be noarch:

 BuildArch: noarch

BuildRequires

In the typical case, since Mageia 9, use:

 BuildRequires: pyproject-rpm-macros
 BuildRequires: python3-devel

For older releases or for setup.py builds:

 BuildRequires: python3

If you are building a C extension-modules, use python3-devel, but leave away python3 (which is requires by python3-devel anyway):

 BuildRequires: python3-devel

As needed add one of:

 BuildRequires: python3-setuptools
 BuildRequires: python3-pip

Requires

  • Please do not specify python3 as a requirement for your package. It will be added automatically in the correct way.
  • The %py_requires macro is no longer needed and has been removed.

Sometimes we need to exclude modules from autorequires  :

 %global __requires_exclude python3dist\\(enum34\\)

Automatically-generated dependencies take the form python3dist(modname) .

Provides

Packages shouldn’t have explicit provides, as they are automatically added in rpmbuild itself.

But usually we don't want to provide private Python extension libs so please consider using the following:

 # we don't want to provide private python extension libs
 %global __provides_exclude_from %{python3_sitearch}/.*\\.so

%prep

Typically:

 %autosetup -n %{fname}-%{version} -p1

%build

Typically:

 %pyproject_wheel

or for setup.py build

 %py3_build

Do not use the following options for setup.py build:

  • '--executable'
  • '--plat-name'

%install

Typically: or for setup.py install

 %py3_install

Do not use the following options for setup.py install:

  • '--optimize' or -O': see above
  • '--record': this is done automatically
  • '--compile' (is default anyway), '--no-compile' (brb-python-bytecompile would compile later anyway)

The macro %pyproject_save_files can be used to include all files from site_packages. The macro takes as argument the directories where the module is stored For example:

 %pyproject_install
 %pyproject_save_files dns

%check

For example:

 %check
 PYTHONPATH=%{buildroot}%{python3_sitelib} %{__python3} -m unittest discover -s test -p "unittest*.py"

If a module don't have a test suite, a minimal check for a module can be:

 %check
 export PYTHONPATH=%{buildroot}%{python3_sitearch}
 %{__python3} -c 'import %{module}; print(%{module}.version)'

%files

Typically:

 %files
 %%doc README
 %{python3_sitelib}/*dist-info
 %{python3_sitelib}/%{fname}

When not using %pyproject macros, dist-info is replaced with egg-info.

When the macro %pyproject_save_files has been used, the section is now typically:

 %files -f %{pyproject_files}
 %doc README

Macros

The following macros are defined in /etc/rpm/macros.d/:

 %python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")
 %python_sitelib	%(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")
 %python_version	%(%{__python} -c "import sys; print(sys.version[0:3])")
 
 %pyver	%(python -V 2>&1 | cut -f2 -d" " | cut -f1,2 -d".")
 
 %py_prefix              %(python -c "import sys; print sys.prefix" 2>/dev/null || echo PYTHON-NOT-FOUND)
 # backward compatibility
 %py_libdir              %py_purelibdir
 %py_platlibdir          %(python -c 'import distutils.sysconfig; print distutils.sysconfig.get_python_lib(standard_lib=1,plat_specific=1)' 2>/dev/null || echo PYTHON-LIBDIR-NOT-FOUND)
 %py_purelibdir          %(python -c 'import distutils.sysconfig; print distutils.sysconfig.get_python_lib(standard_lib=1,plat_specific=0)' 2>/dev/null || echo PYTHON-LIBDIR-NOT-FOUND)
 %py_incdir              %(python -c 'import distutils.sysconfig; print distutils.sysconfig.get_python_inc()' 2>/dev/null || echo PYTHON-INCLUDEDIR-NOT-FOUND)
 %py_sitedir             %py_puresitedir
 %py_platsitedir         %(python -c 'import distutils.sysconfig; print distutils.sysconfig.get_python_lib(plat_specific=1)' 2>/dev/null || echo PYTHON-LIBDIR-NOT-FOUND)
 %py_puresitedir         %(python -c 'import distutils.sysconfig; print distutils.sysconfig.get_python_lib()' 2>/dev/null || echo PYTHON-LIBDIR-NOT-FOUND)
 
 %py_compile(O)  \
 find %1 -name '*.pyc' -exec rm -f {} \\; \
 python -c "import sys, os, compileall; br='%{buildroot}'; compileall.compile_dir(sys.argv[1], ddir=br and (sys.argv[1][len(os.path.abspath(br)):]+'/') or None)" %1 \
 %{-O: \
 find %1 -name '*.pyo' -exec rm -f {} \\; \
 python -O -c "import sys, os, compileall; br='%{buildroot}'; compileall.compile_dir(sys.argv[1], ddir=br and (sys.argv[1][len(os.path.abspath(br)):]+'/') or None)" %1 \
 }
 
 %__python3 /usr/bin/python3
 %python3_sitelib %(%{__python3} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")
 %python3_sitearch %(%{__python3} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")
 %python3_version %(%{__python3} -c "import sys; print(sys.version[0:3])")
 %py3_prefix %(%{__python3} -c "import sys; print(sys.prefix)" 2>/dev/null || echo PYTHON-NOT-FOUND)
 %py3_platsitedir %python3_sitearch
 %py3_puresitedir %python3_sitelib
 %py3_incdir %(%{__python3} -c 'from distutils.sysconfig import get_python_inc; print(get_python_inc())' 2>/dev/null || echo PYTHON-INCLUDEDIR-NOT-FOUND)
 %py3dir %{_builddir}/python3-%{name}-%{version}-%{release}
 
 %py3_setup setup.py
 
 %py3_shbang_opts -s
 
 %py3_build() %{expand:\
 CFLAGS="%{optflags}" %{__python3} %{py3_setup} %{?py3_setup_args} build --executable="%{__python3} %{py3_shbang_opts}" %{?1}\
 }
 
 %py3_install() %{expand:\
 CFLAGS="%{optflags}" %{__python3} %{py3_setup} %{?py3_setup_args} install -O1 --skip-build --root %{buildroot} %{?1}\
 }


Usage sample of %py3_build :

If you need something like :

 python3 setup.py build --use-system-libraries --offline

you can write :

%py3_build -- --use-system-libraries --offline

Tools

There is a tool that can help you to package Python modules from PyPI : https://bitbucket.org/bkabrda/pyp2rpm

It is packaged for Mageia, so you just have to install pyp2rpm. The spec files it generates follow the recommended guidelines.


Samples

Here is a sample of a package build for Python 3 and even including a -doc-subpackage.


%define upstream_name	fdb

Name:		python-fdb
Summary:	Firebird RDBMS bindings for Python
Version:	1.7
Release:	%mkrel 3
Source0:	https://pypi.io/packages/source/f/%{upstream_name}/%{upstream_name}-%{version}.tar.gz
URL:		https://www.firebirdsql.org/
Group:		Development/Python
License:	BSD
BuildArch:	noarch
BuildRequires:	firebird-devel
BuildRequires: python3dist(setuptools)
BuildRequires: pyproject-rpm-macros

%description
Set of Firebird RDBMS bindings for Python. 

%package -n python3-%{upstream_name}
Summary:        Firebird RDBMS bindings for Python 3
%{?python_provide:%python_provide python3-%{upstream_name}}


%description -n python3-%{upstream_name}
Set of Firebird RDBMS bindings for Python.


%package doc
Summary:        Documentation for %{name}
Group:          Documentation
License:        BSD


%description doc
Documentation files for %{name}.


%prep
%autosetup -n %{upstream_name}-%{version}


%build
%pyproject_wheel


%install
%pyproject_install
%pyproject_save_files firebird


%files -n python3-%{upstream_name} -f %{pyproject_files}
%doc README
%license LICENSE.TXT


%files doc
%doc docs/* 
%license LICENSE.TXT

References

Policy in other distributions