(pre-publish) PEP 771: Default Extras for Python Software Packages

I think a similar point came up during the discussion of the original PEP draft, so as written currently, the PEP tries to address this and states:

If the same package is specified multiple times in an installation command or dependency tree, the default extras must be installed if any of the instances of the package are specified without extras. For instance:

pip install package package[extra2]

should install the default extras.

I think this provides an explicit answer to the case you are asking about, but let me know if you would like this clarified further.

For example, we could add a second example to say that if we had the following dependency tree:

A
    X (default)
    Y
        B
            A[Y]

Then if installing A, then X should be installed. However, let me know if the current wording is sufficient for you?

I think a similar point came up during the discussion of the original PEP draft, so as written currently, the PEP tries to address this and states:

If the same package is specified multiple times in an installation command or dependency tree, the default extras must be installed if any of the instances of the package are specified without extras. For instance:

pip install package package[extra2]

should install the default extras.

I think this provides an explicit answer to the case you are asking about, but let me know if you would like this clarified further.

It seems that this is the only sensible solution, but it’s worth noting I think this will be the first PEP to specify what tools should do with dependency trees. Which makes me a little uncomfortable with its implications.

I think it might be better to reword it to something like: “If the same package is specified, or collected, multiple times in an installation command then the default extras must be installed if any of the instances of the package are specified without extras.”

Maybe this is a distinction without a difference though.

From my uv/pubgrub perspective, the relevant property to uphold is that the requirements of one package may not influence the interpretation of the requirements of any other package, because this can’t be modeled by the kind of (SAT) solver that pubgrub is, which requires immutability of dependency edges once they are added (and i expect that this applies to most resolves, as the alternative would require a global solver rather than an incremental one). I already interpreted the spec so that extras are purely additive, but additional examples are always helpful. I wouldn’t use cyclical dependencies though, as a tool could reasonably reject them as unsupported.

3 Likes

Thanks, I think it does. I’m still concerned that the edge cases could be very complex to explain, and may not even be implementable. I think it’ll need to be a prerequisite before the PEP gets accepted that there’s a working implementation - quite probably in both pip and uv, as they use different resolvers with different limitations. At the very least we’d need confirmation from both projects that the PEP is implementable.

There’s definitely a transition problem, though. If A depends on B, and B in turn depends on A, then currently this is fine. Under the new PEP, though, if A defines a default extra, it’s now impossible to override that default extra, as the fact that B depends on the “base” A forces the default extra to be selected. And if a new version of B is released that depends on A[minimal] instead, that won’t work with older versions of A that don’t declare the “minimal” extra.

That’s a good point, and it’s worth noting that not all installer algorithms even see the full dependency tree until they have locked in choices about what dependencies a requirement has. I don’t think that’s an issue, though, as with the interpretation given, a bare package will always mean “the package plus its default extra dependencies”.

I do think that there needs to be some discussion of this in “How to teach this” - specifically, if your project depends on package A, and A introduces a new default dependency, what should you do? As we see above, it’s not immediately obvious, and “talk to the authors of A” isn’t always as easy as it might be - you may not even know that A introduced a default extra.

The published version has now been updated, and I have now started a new thread here:

1 Like