Skip to content

Commit

Permalink
Allow -p to use complex Python version requests in uv pip compile (
Browse files Browse the repository at this point in the history
…#11486)

Closes #11285
Closes #11437

This changes `-p` from an alias of `--python-version` to `--python`
while retaining backwards compatibility for `--python-version`-like
fallback behavior when the requested version, e.g., `-p 3.12`, cannot be
found.

This was initially implemented with a hidden `--python-legacy` flag
which allows us to special case the short `-p` flag — unlike the
implementation in #11437. However, after further discussion, we decided
the behavior difference between `-p` and `--python` would be confusing
so now `-p` is an alias for `--python` and `--python` is special-cased
when a version is used.

Additionally, we now respect the `UV_PYTHON` environment variable, but
it is ignored when `--python-version` is set. If you want different
`--python-version` and `--python` values, you must do so explicitly. I
considered banning this, but it is valid for e.g. `--python pypy
--python-version 3.12`
  • Loading branch information
zanieb authored Feb 13, 2025
1 parent 63b080e commit 45bc7bf
Show file tree
Hide file tree
Showing 5 changed files with 583 additions and 71 deletions.
24 changes: 16 additions & 8 deletions crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1079,15 +1079,23 @@ pub struct PipCompileArgs {

/// The Python interpreter to use during resolution.
///
/// A Python interpreter is required for building source distributions to
/// determine package metadata when there are not wheels.
/// A Python interpreter is required for building source distributions to determine package
/// metadata when there are not wheels.
///
/// The interpreter is also used to determine the default minimum Python version, unless
/// `--python-version` is provided.
///
/// The interpreter is also used to determine the default minimum Python
/// version, unless `--python-version` is provided.
/// This option respects `UV_PYTHON`, but when set via environment variable, it is overridden
/// by `--python-version`.
///
/// See `uv help python` for details on Python discovery and supported
/// request formats.
#[arg(long, verbatim_doc_comment, help_heading = "Python options", value_parser = parse_maybe_string)]
/// See `uv help python` for details on Python discovery and supported request formats.
#[arg(
long,
short,
verbatim_doc_comment,
help_heading = "Python options",
value_parser = parse_maybe_string
)]
pub python: Option<Maybe<String>>,

/// Install packages into the system Python environment.
Expand Down Expand Up @@ -1170,7 +1178,7 @@ pub struct PipCompileArgs {
///
/// If a patch version is omitted, the minimum patch version is assumed. For
/// example, `3.8` is mapped to `3.8.0`.
#[arg(long, short, help_heading = "Python options")]
#[arg(long, help_heading = "Python options")]
pub python_version: Option<PythonVersion>,

/// The platform for which requirements should be resolved.
Expand Down
33 changes: 29 additions & 4 deletions crates/uv/src/commands/pip/compile.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::collections::BTreeSet;
use std::env;
use std::path::Path;
use std::str::FromStr;
use std::sync::Arc;

use anyhow::{anyhow, Result};
Expand Down Expand Up @@ -86,14 +87,14 @@ pub(crate) async fn pip_compile(
no_build_isolation: bool,
no_build_isolation_package: Vec<PackageName>,
build_options: BuildOptions,
python_version: Option<PythonVersion>,
mut python_version: Option<PythonVersion>,
python_platform: Option<TargetTriple>,
universal: bool,
exclude_newer: Option<ExcludeNewer>,
sources: SourceStrategy,
annotation_style: AnnotationStyle,
link_mode: LinkMode,
python: Option<String>,
mut python: Option<String>,
system: bool,
python_preference: PythonPreference,
concurrency: Concurrency,
Expand All @@ -103,6 +104,29 @@ pub(crate) async fn pip_compile(
printer: Printer,
preview: PreviewMode,
) -> Result<ExitStatus> {
// Respect `UV_PYTHON`
if python.is_none() && python_version.is_none() {
if let Ok(request) = std::env::var("UV_PYTHON") {
if !request.is_empty() {
python = Some(request);
}
}
}

// If `--python` / `-p` is a simple Python version request, we treat it as `--python-version`
// for backwards compatibility. `-p` was previously aliased to `--python-version` but changed to
// `--python` for consistency with the rest of the CLI in v0.6.0. Since we assume metadata is
// consistent across wheels, it's okay for us to build wheels (to determine metadata) with an
// alternative Python interpreter as long as we solve with the proper Python version tags.
if python_version.is_none() {
if let Some(request) = python.as_ref() {
if let Ok(version) = PythonVersion::from_str(request) {
python_version = Some(version);
python = None;
}
}
}

// If the user requests `extras` but does not provide a valid source (e.g., a `pyproject.toml`),
// return an error.
if !extras.is_empty() && !requirements.iter().any(RequirementsSource::allows_extras) {
Expand Down Expand Up @@ -189,8 +213,8 @@ pub(crate) async fn pip_compile(
let request = PythonRequest::parse(python);
PythonInstallation::find(&request, environment_preference, python_preference, &cache)
} else {
// TODO(zanieb): The split here hints at a problem with the abstraction; we should be able to use
// `PythonInstallation::find(...)` here.
// TODO(zanieb): The split here hints at a problem with the request abstraction; we should
// be able to use `PythonInstallation::find(...)` here.
let request = if let Some(version) = python_version.as_ref() {
// TODO(zanieb): We should consolidate `VersionRequest` and `PythonVersion`
PythonRequest::Version(VersionRequest::from(version))
Expand All @@ -216,6 +240,7 @@ pub(crate) async fn pip_compile(
&& python_version.minor() == interpreter.python_minor()
};
if no_build.is_none()
&& python.is_none()
&& python_version.version() != interpreter.python_version()
&& (python_version.patch().is_some() || !matches_without_patch)
{
Expand Down
Loading

0 comments on commit 45bc7bf

Please sign in to comment.