[Distutils] abstract build system approaches redux
Donald Stufft
donald at stufft.io
Thu Mar 3 08:44:56 EST 2016
> On Mar 3, 2016, at 8:19 AM, Nick Coghlan <ncoghlan at gmail.com> wrote:
>
> On 3 March 2016 at 10:43, Robert Collins <robertc at robertcollins.net> wrote:
>> Python vs CLI - I don't care enough to argue. I think a CLI is better
>> in this space, as running commands is the lingua franca of CLI's;
>> previously Donald has advocated for that as well, but his proposal is
>> now a Python API. *shrug*. I want the BDFL-Delegate to choose.
>
> I'm happy to let the discussion run for the other open questions you
> mention, but I'm now prepared to pronounce on this aspect based on one
> specific factor: I don't want to mandate that all future build systems
> for Python projects (whether front ends or back ends) must be written
> in Python.
>
> If somebody comes up with an all-singing, all-dancing Python build
> system that happens to be written in Go, or Rust, or Haskell, or that
> they made by adapting an existing build system for another language
> ecosystem to have native support for also building Python packages,
> I'd like for the Python packaging ecosystem to be able to handle that
> without significant fuss.
>
> Attaining that level of cross-language interoperability then
> necessarily means defining the formal build system abstraction
> interface at the CLI boundary, rather than as a Python API.
>
> Defining a helper library/framework to make it *easier* to write new
> build systems in Python would still make sense, but that can be done
> in the usual way that any other library gains widespread acceptance:
> by being easier to use than a "DIY" approach when it comes to directly
> implementing the underlying interoperability specification.
I'd like to push back against this, speaking as someone who was originally pro
CLI:
I think that a Python API is actually better for one reason: introspection.
I cannot think of a particularly great way to have a CLI based build tool
*evolve* with new APIs that are not user facing without requiring end users
to do something like mark "ok now my thing is X compatible" or without
inventing some sort of protocol negotiation phase.
For instance, let's say that we say that we need an ``metadata`` API that can
output metadata 1.x style metadata. That's great and right now we can just
assume that it exists. However, let's say in the future we add a metadata 2.0
spec that isn't backwards compatible. Now how do we handle this? A new version
of pip can't just assume that the ``metadata`` command is going to always
return 2.x metadata now, because that would break all existing build tools so
it needs some method to determine what capabilities a particular build system
has.
I see a few options:
* If we're using a CLI based thing, we need to create a negotiation phase,
which I think is a bad idea because it's kind of complicated and error prone.
Looking at TLS or HTTP, there's more than one bug that exists because of
this.
* If we're using a CLI based thing, we need to bake into the file what the
capabilities of the build system is. Maybe using something like:
generate-metadata-2: true
# OR
metadata2-generation-command: ${PYTHON} -m generate-metdata
However, I think this is bad because it makes it harder to get automatic
"wins" for new features because you have to convince every single author to
go and modify their file to tell pip (or whatever) that this new feature is
available as well as then needing to force a >= in their build dependencies
because they mandating some new feature by baking it directly into their
project.
* If we're using a Python based API, we can simply just say that there can be
no backwards incompatible changes made to an API name once defined. If we
want to create a new function that produces the new style metadata, then we
can simply do a check like:
if hasattr(api, "metadata2"):
# Do Metadata 2.x Code
else:
# Do Metadata 1.x Code
This not only allows all projects to automatically start using this new
feature as soon as a build tool implements it, getting automatic wins, but it
also makes it trivial for a project to support both old and new versions of
pip, since there will be a different API name for a backwards incompatible
change. Old pip would just use the old code, and new pip would use the new
code.
The only real benefits I can see to using a CLI based over a Python based are:
* We move some code out of pip into each individual build backend, making it
clearer the process boundaries. This is a nice thing, and it is the primary
reason I wanted a CLI based API. However I don't think it outweighs the
ability to introspect what API methods are available.
* We make it easier to use a non Python based build system. This is also a nice
thing, however I don't think it should be a major decider in what API we
provide. Any reasonable build system is going to have to be available via
``pip install`` in some fashion, so even if you write your build system in
Go or Rust, you're going to have to create a Python package for it anyways,
and if you're doing that, adding a tiny shim is pretty trivial, something
like:
import os.path
import subprocess
BIN = os.path.join(os.path.dirname(__file__), "mytool")
def some_api_function(*args, **kwargs):
flags = convert_args_kwargs_to_flags(*args, **kwargs)
subprocess.run(BIN, *flags, check=True)
I don't believe it to be a substantial burden to need to write a tiny wrapper
if you're going to do something which I believe is going to be very unlikely.
In the end, I think this comes down that we shouldn't optimize for the least
common case, at the expense of the ability to more easily evolve the API in the
future.
-----------------
Donald Stufft
PGP: 0x6E3CBCE93372DCFA // 7C6B 7C5D 5E2B 6356 A926 F04F 6E3C BCE9 3372 DCFA
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 842 bytes
Desc: Message signed with OpenPGP using GPGMail
URL: <http://mail.python.org/pipermail/distutils-sig/attachments/20160303/cc827984/attachment-0001.sig>
More information about the Distutils-SIG
mailing list