Discussion: Macros for Python Specfiles

Nick Coghlan ncoghlan at redhat.com
Mon May 27 03:46:10 UTC 2013


On 05/25/2013 03:13 AM, Toshio Kuratomi wrote:
> 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}\
>      }

Given the upstream flux, I'd say "don't change this yet". We're punting 
on several of the issues that are specific to building from source to 
metadata 2.1 (since they involve bigger changes than just cleaning up 
the installation side of things).

> 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?

Because pymeta.json is a generated file, the question becomes "How do 
you generate pymeta.json, if all you have is a source tarball?".

For metadata 2.0, the command for that is probably going to be "python 
setup.py dist_info".

Killing the reliance on setup.py on the build side now won't be 
happening until metadata 2.1 at the earliest.

>> 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

pip 1.4 should include the necessary bits to handle the wheel generation 
(http://www.pip-installer.org/en/latest/usage.html#pip-wheel).

>
> # 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} ).

Yeah, support for sysconfig schemes is the main advantage wheel offers 
over the previous egg format (although it does in turn depend on 
upstream projects identify files correctly).

> 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?

Eventually we want to have the build commands be entry points that 
reference Python callables, but I've decided it makes more sense to 
postpone that aspect and focus on the installation side for now.

> * 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.

I think it should be package-by-package for now. Some packages (like 
Twisted) are known not to support installation from the current 
incarnation of the wheel format because they need to run code following 
the install. "./setup.py install" currently lets them do that, but 
wheels won't support postinstallation hooks until metadata 2.0 is available.

> * 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?

For us, probably not a lot because we use separate build servers anyway, 
with binary RPMs for deployment systems. The payoff is bigger upstream 
where wheels act as a cross-platform binary distribution format.

> * 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.

Yeah, I agree - wait and see is the better path here.

>> 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.

I'll be publishing updated drafts of PEP 426 (metadata 2.0) and PEP 440 
(the associated versioning spec) this week. Something they try to do is 
make clear that the kinds of dependencies appropriate for library 
developers (which should have generous assumptions regarding forward 
compatibility) differ from those that are suitable for system 
integrators (who may pin particular tested versions)

> 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.

I'm guessing you meant "python-foo >= 1.2" here?

> 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.

If the upstream project doesn't do maintenance releases, then there's 
still going to be some kind of modification of the metadata or the build 
commands required for cases where an application needs a bug fix that 
has been backported from the next feature release.

That said, I believe pip supports version overrides which let an 
integrator say "trust me, this version is fine, the upstream dependency 
metadata is wrong".

So, perhaps the moral of the story here is that going through pip 
instead of invoking setup.py directly lets you override quite a few bad 
default behaviours in setuptools, which means *pip* might be an 
appropriate choice as our Python build helper tool :)

That would also let us transparently upgrade to any new metabuild hooks 
we come up with upstream - such hooks will only happen if the pip 
developers agree to implement them upstream, so we may as well take 
advantage of that downstream.

Cheers,
Nick.

-- 
Nick Coghlan
Red Hat Infrastructure Engineering & Development, Brisbane

Test Automation Team Lead
Beaker Development Lead (http://beaker-project.org/)
PulpDist Development Lead (http://pulpdist.readthedocs.org)


More information about the python-devel mailing list