Skip to content

Conversation

@notatallshaw
Copy link
Member

Fixes #13221

This PR adds two new flags --all-releases and --only-final, they control package selection with the exact same semantics as --no-binary and --only-binary, but for pre vs final releases instead of binary vs. source distributions.

They are mutually exclusive with --pre, as there are edge cases to do with the semantics of --pre and these flags I didn't want to have to define. However, when only --pre is used it is converted to the equivalent --all-releases :all: in the code, to keep the logic simple.

The main feature I think users will be interested is only allowing final releases, to prevent pre-releases from being selected in any situation, e.g.

$ pip install --dry-run opentelemetry-exporter-prometheus  --only-final ":all:"
ERROR: Ignored the following yanked versions: 1.10a0, 1.12.0rc1
ERROR: Could not find a version that satisfies the requirement opentelemetry-exporter-prometheus (from versions: 0.12b0, 0.13b0, 0.14b0, 0.15b0, 0.16b0, 0.16b1, 0.17b0, 0.29b0, 0.30b0, 0.30b1, 0.32b0, 0.33b0, 0.34b0, 0.35b0, 0.36b0, 0.37b0, 0.38b0, 0.39b0, 0.40b0, 0.41b0, 0.42b0, 0.43b0, 0.44b0, 0.45b0, 0.46b0, 0.47b0, 0.48b0, 0.49b0, 0.49b1, 0.49b2, 0.50b0, 0.51b0, 0.52b0, 0.52b1, 0.53b0, 0.53b1, 0.54b0, 0.54b1, 0.55b0, 0.55b1, 0.56b0, 0.57b0, 0.58b0, 0.59b0)
ERROR: No matching distribution found for opentelemetry-exporter-prometheus

@notatallshaw notatallshaw force-pushed the final-and-prerelease-control branch from 5b4b0c1 to dbd03ab Compare November 15, 2025 03:43
@potiuk
Copy link
Contributor

potiuk commented Nov 15, 2025

Very nice - and very neeeded :)

Copy link
Member

@ichard26 ichard26 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass review. I'll need to take another look at this. Overall, logic looks good, but I'd like to take another look at the code.

Comment on lines +191 to +196
if finder.release_control is not None:
# Use ordered args to preserve the user's original command-line order
# This is important because later flags can override earlier ones
for attr_name, value in finder.release_control.get_ordered_args():
args.extend(("--" + attr_name.replace("_", "-"), value))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't wait until we eliminate the subprocess build env installer so we can just let this configuration be inherited through the finder for free.

Comment on lines +46 to +47
self.cmd_opts.add_option(cmdoptions.all_releases())
self.cmd_opts.add_option(cmdoptions.only_final())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I noted in the --uploaded-prior-to PR, I believe it would be better if we grouped our command options more aggressively. Any command that accepts --no-binary (and friends) should also support --only-final and --all-releases for free.

This can be addressed as a follow up since the scope would be larger than any of these two PRs.

"""
return self._order[:]

def allows_prereleases(self, canonical_name: str) -> bool | None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def allows_prereleases(self, canonical_name: str) -> bool | None:
def allows_prereleases(self, canonical_name: NormalizedName) -> bool | None:

If this API is going to break on unnormalized names, let's enforce that in the function signature.

Comment on lines +43 to +45
def handle_mutual_excludes(
self, value: str, target: set[str], other: set[str], attr_name: str
) -> None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a docstring describing what this does. It's not too bad to grok manually, but some help can't hurt :)

from pip._internal.exceptions import CommandError


class ReleaseControl:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, could we replace this with a dataclass? I don't think this object is performance sensitive enough slots is essential:

from dataclasses import dataclass, field

# TODO: add slots=True when Python 3.9 is dropped
@dataclass
class ReleaseControl:
    """Helper for managing which release types can be installed."""

    all_releases: set[str] = field(default_factory=set)
    only_final: set[str] = field(default_factory=set)
    # Track the order of arguments as (attribute_name, value) tuples
    # This is used to reconstruct arguments in the correct order for subprocesses
    _order: list[tuple[str, str]] = field(
        init=False, default_factory=list, compare=False, repr=False
    )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proposal: New arguments to control pre-releases

3 participants