Discussion: Macros for Python Specfiles

Toshio Kuratomi a.badger at gmail.com
Fri May 24 17:13:08 UTC 2013


On Tue, May 07, 2013 at 01:57:01PM +1000, Nick Coghlan wrote:
> On 05/06/2013 10:43 PM, Bohuslav Kabrda wrote:
> >Hi all,
> >as mentioned in [1], I'd like to start a discussion about proposed Python macros.
> >The full macro file can be seen at [2] and an example diff of converted spec at [3].
> >
> >The important macros from the proposal are:
> >
> >%py_default_filter # will filter all *.so file provides from /usr/lib{64}/pythonX.Y/site-packages

This one has been approved

> >%py[3]_build # will run setup.py build with proper args/flags
> >%py[3]_install # will run setup.py install with proper args
> >
I have reservations about these.  The first one is general to these types of
macros so I'll make the case not to use these macros at all here.
Subsequent portions of this message will deal with problems I have with the
macros should we choose to go this route.

RPM spec files are mostly shell scripts.  This makes it easy for system
administrators to make the jump from locally installing a package to
building an rpm to becoming a valued Fedora packager because, at its heart,
an rpm spec file is just recording the steps that they would have taken
anyway.

Macros form another layer on top of the shell scripts that system
administrators have to learn; a layer that they can't then directly apply
back to their local installs.

As the Zen of python says, "Explicit is better than implicit." In this case
the macros are moving us away from being explicit for only a little gain.
(I'll acknowledge and talk about the gain in the next section).  Moreover,
for every command line that we're replacing, we are replacing them with
multiple macros, three of which are publically visible and all of which
would need to be understood by someone who wanted to know what the macros do
and modify their behaviour:

The current command line for building:
   %{__python} setup.py build

The macros to implement this for the new style:
  %{__python} setup.py build
  %py_build %py2_build
  %py2_build %py_rt_build %__python
  %py_rt_build() %{expand:\
    CFLAGS="$RPM_OPT_FLAGS" %{!?1:%{__python}}%{?1:%{1}} %{py_setup}
    %{?py_setup_args} build %{?py_build_args}\
    }


> >I already proposed this to fpc [4], but it seems that there is a disagreement [5] about the %py_{build,install} macros. This is why I'd like to start a broader discussion about them here.
> >Thank you for your opinions.
> 
> The potential advantage I see to the py_build and py_install macros
> is that we're actively trying to move away from always relying on
> setup.py upstream.

<nod> This is the advantage that I see to macroizing as well.  While writing
out the command line makes it easy for individual packagers to experiment
with changes to the common workflow and then enhance the guidelines by
submitting the results of their experiments as modifications to the default
command line invocations in the guidelines, macroizing makes it easy for a
central decision maker to update how all packages do things.

> Thus, the idea of a helper script that calls
> setup.py if it is present, or looks up the right build command in
> pymeta.cfg if *that* is present sounds reasonable to me.
> 
If we're going to hide the command line invocation behind a macro, I did
propose in the bug report that we use a helper script rather than pure
macros to implement it:
  https://bugzilla.redhat.com/show_bug.cgi?id=953704#c10

Pure rpm macros are hard to read and understand and differ enough from shell
that someone attempting to carry their knowledge from that domain will get
lost.  A script would alleviate that.

Could you tell us more about pymeta.cfg?  is it the pymeta.json that I see
mentioned in the draft PEP?  Another data format of the same information?
Or something different?

> Similarly, we're going to try to move away from invoking setup.py at
> install time, and instead install from wheel files with a
> post-install hook registered in the package metadata.
> 

So.. in talking about using wheel, I had a look at what we can do now.  This
is what the landscape looked like to me a month ago when I tried it out:

# This stays the same as it is now
Source0: sdist-1.0.tar.gz

# New BuildRequires.  python-wheel isn't yet packaged.
# python-pip needs to have the equivalent of the --root flag; this has
# recently been updated in Fedora to a version that has this capability
BuildRequires: python-wheel
BuildRequires: python-pip >= 1.3.0

# This also stays the same as it is now
%prep
%setup -q -n %{srcname}-%{version}
%patch0 [..]

%build
# here's the first difference.  We build a wheel instead of just the
# compiled code
%{__python} setup.py bdist_wheel

%install
# And then we install the wheel into an expanded form on the filesystem
pip install --root %{buildroot} dist/*.whl

I actually got stuck on the install section for a while (python-wheel
doesn't have a --root capable install command and python-pip was too old in
Fedora at the time) so I haven't looked further than that to see if there
were different files on disk as a result of installing from a wheel... my
understanding is that that is one of the promises of the wheel format (for
instance, locale files ending up in %{_datadir}/locale instead of in
%{python_sitelib} ).

What I see so far:
* The build and install commands look macro-able
* This uses setup.py but from your other comment, I guess that there's
  a different way to do this that uses an alternate tool?
* This seemed to work without any support from setup.py but I was using a
  very simple package as my first try at this.  We probably need to try this
  with more complex package -- in particular I wonder whether we will be
  able to use this for all packages, most packages, or just some packages.
  That affects whether we want to make this something that is chosen
  centrally vs chosen by the individual package maintainers.
* If the package builds using setup.py and builds either using the old
  strategy or the new strategy, what are the benefits of the new strategy?
* As mentioned earlier, I heard that one of the benefits of the new strategy
  was that it would place certain types of files into FHS compliant locations.
  This is great but it seems like it won't always be easy or desirable to
  macroize that in the %files section.  If the package maintainer has to
  adjust the %files section explicitly, it might be better for them to be in
  control of switching the build strategy as well.


> This will hopefully become clearer once I finish the next draft of
> PEP 426 (Python's distribution metadata 2.0). 

<nod>  My suggestion is that if we do want to macroize this to make it easy
to centrally switch the strategy used to build and install python modules we
are putting hte cart before the horse here.  We should first figure out what
the new strategy is and write that up.  Then figure out how to write macros
that allow us to switch between the two.  Writing the macros first and then
hoping that they cover all of the things that need to be changed in order to
effect the change is either going to lead to an incomplete solution (which
will require packagers to modify their spec files multiple times for the
changing guidelines) or overengineering.as we make it account for potential
quirks in the tooling that never appear in the future.

> 
> The two parts likely to be of most interest to those on this list:
> 
> Development activities:
> https://bitbucket.org/ncoghlan/misc/src/default/pep-0426.txt#cl-124
> Dependencies:
> https://bitbucket.org/ncoghlan/misc/src/default/pep-0426.txt#cl-577
> 

(This section is getting into a tangent from the original topic).

Read through those sections -- one thing that I noticed is that how to use
the version information in a dependency is not spoken about.  Something that
would be nice from a distribution POV is to treat versions differently if
you are running a program (including testing) versus deploying it.  This is
something that pkg_resources gets wrong.

Example:

python-foo-1.0 is upstream and python-foo-1.0-1 is the Fedora package.

python-foo is a large framework with several different python modules that
don't all need to be used together.

A security issue is found in the package.  upstream releases python-foo-1.2
with the fix as well as some API changes to specific modules.  Fedora
applies a backport of the security fix to their python-foo-1.0-2 package.

The pybar application makes use of the python-foo modules.  They only use
the modules whose API has not changed between python-foo-1.0 and
python-foo-2.0.  Due to the security update, they update their Requirement
to python-foo >= 2.0.

now -- if I'm a developer or a sysadmin installing from pypi; I want pip
install to (which processes the dependencies recursively) to get
python-foo-1.2.

If I'm a packager for Fedora, I want pybar to use the python-foo-1.0-2
Fedora package when I build and run because I've checked that the API usage
is okay.

If I'm the end user, I want the Fedora pybar package that I've installed to
work with the Fedora python-foo-1.0-2 package.

With pkg_resources, this required patching of the version information in
the setup.py by the packager to account for this other use (bug was fixed
downstream).

A higher level way to think about it is to be able to separate out version
information as it relates to API compatibility from version information as
it relates to working around bugs.

-Toshio
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.fedoraproject.org/pipermail/python-devel/attachments/20130524/34d8aa2e/attachment.sig>


More information about the python-devel mailing list