[Distutils] Environment marker expression types

Nick Coghlan ncoghlan at gmail.com
Fri Apr 26 08:52:50 CEST 2013


On Fri, Apr 26, 2013 at 4:05 PM, PJ Eby <pje at telecommunity.com> wrote:
> On Thu, Apr 25, 2013 at 9:50 PM, Nick Coghlan <ncoghlan at gmail.com> wrote:
>> 5. The installer evaluates the conditional metadata as appropriate
>> before writing the metadata out to the installation database and
>> invoking the post-install hook. Post-installation, the top level
>> metadata includes both the unconditional metadata *and* any
>> conditional metadata that applies to the current system.
>
> ISTM that this does away with some of the benefits of e.g. fat wheels
> and the ability to share source across multiple Python versions (as
> distros sometimes like to do).  It also seems to have very little
> gain, since if you are reading the metadata, you've probably already
> imported distlib anyway.  ;-)

OK, I'm convinced - no install time transforms, if you need the full
set of dependencies at run time, you have to poke around in the
conditionals field to see if there is anything relevant.

> In general, I favor the minimum possible transformations between
> wheels and on-disk format, simply because it means fewer conditional
> paths in APIs that need to support both.  If you're going to resolve
> the dependencies in a wheel, you have to parse the conditionals, so
> again it doesn't save much to not parse them.
>
> If you want to increase parsing efficiency in the presence of
> conditionals, I would suggest nesting the conditionals in individual
> fields, or at least using a structure like:
>
>     { 'conditionals': {'requires': [....], 'other-field': [...]}}
>
> As this means that you only have to parse the conditions for fields
> you're actually accessing.  That keeps parsing to a minimum if a given
> query is only looking at unconditional fields.

Yes, I think I prefer this layout for runtime consumption. Getting the
full value for a field would then just be something like:

    # Core dependencies
    deps = meta["requires"]
    # Check dependencies for any specified optional components
    for extra_name in extras_of_interest:
        extra = meta["extras"].get(extra_name)
        if not extra:
            continue
        deps.extend(meta["extras"].get("requires", ()))
    # Check conditional dependencies
    maybe_deps = meta["conditional"].get("requires")
    if maybe_deps:
        for dep in maybe_deps:
            if some_marker_evaluation_api(dep["condition"]):
                deps.extend(dep["entry"])

Good enough for a first draft, anyway :)

distlib would probably evolve some metadata abstraction that hides all
that fiddling behind a property.

> So, my suggestion would be to drop the overloading of extras as
> markers, and structure all conditional data such that only the
> conditionals needed to satisfy a particular inquiry ever need to be
> parsed.  This should optimize the common case (infrequent dependency
> parsing and infrequent conditionals in a simple unpacked structure)
> while still enabling advanced cases such as cross-version or
> cross-platform sharing to work correctly.

Yes, I'm definitely sold on that part.

Cheers,
Nick.

--
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Distutils-SIG mailing list