From Fedora Project Wiki

fp-wiki>ImportUser
(Imported from MoinMoin)
 
(add link to the bug/script and some notes)
 
(7 intermediate revisions by 4 users not shown)
Line 1: Line 1:
<pre>
== Virtual Provides ==
:Version: 0.2.2
:Last Revised: Aug 23, 2006
:ChangeLog:
Update the setuptools/egg section due to a new setuptools in Extras.


</pre>
Dave Malcolm has proposed writing an rpm script to detect, at least, Python Eggs that are installed by a package.  To go along with that, we should have virtual provides that map the package to egg name.
== Hints on how to Package Python modules ==


= Hints on how to Package Python modules =
--[[User:Dmalcolm|Dmalcolm]] 16:13, 14 April 2009 (UTC): I wrote a script to try to auto-extract the Egg deps and turn them into RPM deps.  This was in https://bugzilla.redhat.com/show_bug.cgi?id=451228 (mismatch between the numerous versioned deps in TurboGears' Egg file vs the RPM package).  At the time I meant it more as a proof-of-concept experiment than a proposal for changing how we track python deps, but I'm happy if someone wants to take the idea and run with it.


--[[User:Dmalcolm|Dmalcolm]] 16:13, 14 April 2009 (UTC): note that there are some nasty syntax issues: e.g. Egg versions can contain dash characters, whereas RPM deps can't


== Python version ==
We could copy the ruby/rubygem syntax and have something like this:


In the past (FC3 and earlier) it was mandatory to add the line
  Provides: python(bar) = %{version}
<pre>
  Provides: python(foo) = %{version}
Requires:       python-abi = %(%{__python} -c "import sys ; print sys.version[[3]] ")
  Provides: pythonegg(foo) = %{version}
</pre>
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 ==
  Requires: pythonegg(foo) >= 0.3
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:
  Requires: python(bar)


<pre>
I think that Dave Malcolm's approach should be expandable to:
%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
* Providing normal python modules: look for them on the filesystem in site-packages.
</pre>
* Providing Python Eggs: Examine the egg info.
* Requiring Python Eggs: Examine the egg info.


On an i386 python-2.4 system, for example, %{python_sitelib} will be <code>/usr/lib/python2.4/site-packages</code>. During %install, or when listing %files, you can use the %{python_sitelib} macro to specify the path. For example:
Requiring of normal python modules would still have to be done by hand (there's some ways this might be done but they're more complex). This also doesn't attempt to manage submodules of a normal python module: ie:


<pre>
  bzr:
%files
    %{python_sitearch}/bzrlib
%defattr(-,root,root,-)
    # Automatically found:
%dir %{python_sitelib}/modulename
    Provides: python(bzrlib)
%{python_sitelib}/modulename/*.py
%{python_sitelib}/modulename/*.pyc
</pre>


{{Template:Note}} For python modules that include any architecture-specific libraries (like those written in C), you should additionally use:
  bzr-gtk:
    %{python_sitearch}/bzrlib/plugins/gtk
    # Would have to manually specify:
    Provides: python(bzrlib.plugins.gtk)


<pre>
My suggestion for this draft would be to specify submodules manually.  Especially because some submodules will be necessary to specify while others will not (We shouldn't need to specify any submodules of bzrlib that are provided by bzrlib, for instance.)
%{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
</pre>


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})
If we don't want to convert packages to using Requires: python(bar) instead of Requires: python-bar because of the manual nature of the Requires, the pythonegg portion of this draft still has benefits.


{{Template:Warning}} 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.
[[Category:Packaging guidelines drafts]]
 
== setuptools/eggs ==
 
Python packages that use setuptools need to add python-setuptools as a Build''''''Requires and must either add <code>--single-version-externally-managed</code> to the line invoking setup.py in %install, or must add a .pth file containing the path to the egg or egg directory to %{python_sitelib}.
 
* As of setuptools-0.6a11 the setuptools homepage recommends using the <code>--root</code> switch instead of <code>--single-version-externally-managed</code>.  This needs to be looked at further, but seems like it is okay to do this way.
 
[http://peak.telecommunity.com/DevCenter/setuptools Setuptools home page]  
 
Further egg information that needs to be distilled out here:
http://permalink.gmane.org/gmane.comp.python.distutils.devel/2567
http://mail.python.org/pipermail/distutils-sig/2005-November/005399.html
 
== 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 FC4+, 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:
<pre>
%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/
</pre>
 
For Core releases earlier than FC4, you need to generate the .pyc and .pyo files yourself.
 
If your module is using distutils, use the following commands during %install:
 
<pre>
%{__python} setup.py install --skip-build --root $RPM_BUILD_ROOT
%{__python} setup.py install -O1 --skip-build --root $RPM_BUILD_ROOT
</pre>
 
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:
<pre>
%files
%{_bindir}/orient.py
%exclude %{_bindir}/orient.pyc
%exclude %{_bindir}/orient.pyo
</pre>
 
An open bug to address this issue is here: https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=182498

Latest revision as of 16:13, 14 April 2009

Virtual Provides

Dave Malcolm has proposed writing an rpm script to detect, at least, Python Eggs that are installed by a package. To go along with that, we should have virtual provides that map the package to egg name.

--Dmalcolm 16:13, 14 April 2009 (UTC): I wrote a script to try to auto-extract the Egg deps and turn them into RPM deps. This was in https://bugzilla.redhat.com/show_bug.cgi?id=451228 (mismatch between the numerous versioned deps in TurboGears' Egg file vs the RPM package). At the time I meant it more as a proof-of-concept experiment than a proposal for changing how we track python deps, but I'm happy if someone wants to take the idea and run with it.

--Dmalcolm 16:13, 14 April 2009 (UTC): note that there are some nasty syntax issues: e.g. Egg versions can contain dash characters, whereas RPM deps can't

We could copy the ruby/rubygem syntax and have something like this:

 Provides: python(bar) = %{version}
 Provides: python(foo) = %{version}
 Provides: pythonegg(foo) = %{version}
 Requires: pythonegg(foo) >= 0.3
 Requires: python(bar)

I think that Dave Malcolm's approach should be expandable to:

  • Providing normal python modules: look for them on the filesystem in site-packages.
  • Providing Python Eggs: Examine the egg info.
  • Requiring Python Eggs: Examine the egg info.

Requiring of normal python modules would still have to be done by hand (there's some ways this might be done but they're more complex). This also doesn't attempt to manage submodules of a normal python module: ie:

 bzr:
   %{python_sitearch}/bzrlib
   # Automatically found:
   Provides: python(bzrlib)
 bzr-gtk:
   %{python_sitearch}/bzrlib/plugins/gtk
   # Would have to manually specify:
   Provides: python(bzrlib.plugins.gtk)

My suggestion for this draft would be to specify submodules manually. Especially because some submodules will be necessary to specify while others will not (We shouldn't need to specify any submodules of bzrlib that are provided by bzrlib, for instance.)

If we don't want to convert packages to using Requires: python(bar) instead of Requires: python-bar because of the manual nature of the Requires, the pythonegg portion of this draft still has benefits.