From Fedora Project Wiki

Revision as of 16:32, 24 May 2008 by Ravidiip (talk | contribs) (1 revision(s))

:Version: 0.4
:Last Revised: Dec 16, 2007

Hints on how to Package Python modules

Python version

In the past (FC3 and earlier) it was mandatory to add the line

Requires:       python-abi = %(%{__python} -c "import sys ; print sys.version[[3]] ")

to the spec file to require a specific version of the python-abi. This is not needed anymore in FC4 and later because rpm adds a automatic dependency on python(abi) now on its own.

System Architecture

If you are installing anything into the global site_packages directory, use the following trick. First, define python_sitelib at the top of your specfile:

%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}

On an i386 python-2.4 system, for example, %{python_sitelib} will be /usr/lib/python2.4/site-packages. During %install, or when listing %files, you can use the %{python_sitelib} macro to specify the path. For example:

%files
%defattr(-,root,root,-)
%dir %{python_sitelib}/modulename
%{python_sitelib}/modulename/*.py
%{python_sitelib}/modulename/*.pyc

For python modules that include any architecture-specific libraries (like those written in C), you should additionally use:

%{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}

This will ensure the package is installed correctly on multilib architectures. By using these macros instead of hardcoding the directory in the specfile your spec remains compatible with the installed python version even if the diretory structure changes radically (for instance, if python_sitelib moves into %{_datadir})

You shouldn't rely on INSTALLED_FILES, as that will not list directories, which will need to be specified in the %files section as well. Using globs in the %files section is safer.

setuptools/eggs

In the past, Fedora has done the minimal amount to support eggs for upstream distros. As eggs are being adopted more widely upstream we need to have more comprehensive documentation on how to handle this. The following are a summary of the guidelines for reviewers to go over. The complete policy includes examples and rationale for the way we do things.

  • Must: Python eggs must be built from source. They cannot simply drop an egg from upstream into the proper directory.
  • Must: Python eggs must not download any dependencies during the build process.
  • Must: If egg-info files are generated by the modules build scripts they must be included in the package.
  • Must: When building a compat package, it must install using easy_install -m so it won't conflict with the main package.
  • Must: When building multiple versions (for a compat package) one of the packages must contain a default version that is usable via "import MODULE" with no prior setup.
  • Should: A package which is used by another package via an egg interface should provide egg info.

Byte Compiled Files

Python will automatically try to byte compile files when it runs in order to speed up startup the next time it is run. These files are saved in files with the extension of .pyc (compiled python) or .pyo (optimized compiled python). These files are a byte code that is portable across OSes. 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.

If you are only going to build for Fedora Core >= 4 and RHEL >= 5, rpm has a script that will create the files for you. All you have to do is remember to include the files in your spec file. The following are all acceptable ways to accomplish this:

%install
install -d %{python_sitelib}/foo
install -pm 0644 foo.py %{python_sitelib}/foo/

Either:

%files
%dir %{python_sitelib}/foo
%{python_sitelib}/foo/foo.py
%{python_sitelib}/foo/foo.pyc
%{python_sitelib}/foo/foo.pyo

Or:

%files
%dir %{python_sitelib}/foo
%{python_sitelib}/foo/foo.py*

Or even:

%files
%{python_sitelib}/foo/

Fedora releases earlier than 4 and RHEL less than 5 you need to generate the .pyc and .pyo files yourself.

If your module is using distutils or setuptools, use the following commands during %install:

%{__python} setup.py install --skip-build --root $RPM_BUILD_ROOT
%{__python} setup.py install -O1 --skip-build --root $RPM_BUILD_ROOT

And remember to add the .pyc and .pyo files to your %files section.

Including pyos

In the past it was common practice to %ghost .pyo files in order to save a small amount of space on the users filesystem. However, this has two issues: 1. With SELinux, if a user is running python -O [APP] it will try to write the .pyos when they don't exist. This leads to AVC denial records in the logs. 2. If the system administrator runs python -OO [APP] the .pyos will get created with no docstrings. Some programs require docstrings in order to function. On subsequent runs with python -O [APP] python will use the cached .pyos even though a different optimization level has been requested. The only way to fix this is to find out where the .pyos are and delete them.

The current method of dealing with pyo files is to include them as is, no %ghosting.

Unnecessary Byte compilation

From FC4 to current development, the automatic byte compilation of python files that is performed by brp-python-bytecompile byte compiles all files that match *.py This is undesirable for program files in %{_bindir} and %{_sbindir} because the user will probably never invoke these files, only the main program file and python won't use these files. Until the bug is resolved, there are two workarounds: 1. Rename scripts in %{_bindir} to not have a .py extension: For instance, from /usr/bin/orient.py to /usr/bin/orient. 2. Use %exclude to exclude the scripts from the file listing:

%files
%{_bindir}/orient.py
%exclude %{_bindir}/orient.pyc
%exclude %{_bindir}/orient.pyo

An open bug to address this issue is here: https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=182498