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
  • Loading branch information
zanieb committed Feb 13, 2025
1 parent 1e58434 commit 16296d6
Show file tree
Hide file tree
Showing 6 changed files with 403 additions and 4 deletions.
13 changes: 12 additions & 1 deletion crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1170,9 +1170,20 @@ 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 Python interpreter or version to use for resolution.
///
/// In previous versions of uv, `-p` was an alias for `--python-version` in `uv pip compile` but
/// an alias for `--python` in all other commands. This option is provided as a backwards
/// compatible shim, allowing `-p` to behave as `--python` without introducing a breaking
/// change.
///
/// `UV_PYTHON` is respected, but overridden by `--python-version` or `--python`.
#[arg(short, hide = true, help_heading = "Python options")]
pub python_legacy: Option<String>,

/// The platform for which requirements should be resolved.
///
/// Represented as a "target triple", a string that describes the target platform in terms of
Expand Down
67 changes: 65 additions & 2 deletions crates/uv/src/commands/pip/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use uv_resolver::{
InMemoryIndex, OptionsBuilder, PrereleaseMode, PythonRequirement, RequiresPython,
ResolutionMode, ResolverEnvironment,
};
use uv_static::EnvVars;
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
use uv_warnings::warn_user;

Expand Down Expand Up @@ -94,6 +95,7 @@ pub(crate) async fn pip_compile(
annotation_style: AnnotationStyle,
link_mode: LinkMode,
python: Option<String>,
mut python_legacy: Option<String>,
system: bool,
python_preference: PythonPreference,
concurrency: Concurrency,
Expand All @@ -103,6 +105,29 @@ pub(crate) async fn pip_compile(
printer: Printer,
preview: PreviewMode,
) -> Result<ExitStatus> {
// If the user requests both `-p` and `--python` or `--python-version`, error
if let Some(python_legacy) = python_legacy.as_ref() {
if let Some(python) = python.as_ref() {
return Err(anyhow!(
"Cannot specify both `-p` ({python_legacy}) and `--python` ({python}).",
));
}
if let Some(python_version) = python_version.as_ref() {
return Err(anyhow!(
"Cannot specify both `-p` ({python_legacy}) and `--python-version` ({python_version}).",
));
}
}

// Respect `UV_PYTHON` with legacy behavior
if python_legacy.is_none() && python_version.is_none() && python.is_none() {
if let Ok(python) = std::env::var(EnvVars::UV_PYTHON) {
if !python.is_empty() {
python_legacy = Some(python);
}
}
}

// 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 @@ -188,9 +213,30 @@ pub(crate) async fn pip_compile(
let interpreter = if let Some(python) = python.as_ref() {
let request = PythonRequest::parse(python);
PythonInstallation::find(&request, environment_preference, python_preference, &cache)
} else if let Some(python_legacy) = python_legacy.as_ref() {
// `-p` uses backwards compatible behavior and does not fail if it cannot find the requested
// version; previously, this was short for `--python-version`
let request = PythonRequest::parse(python_legacy);
match request {
PythonRequest::Version(..) => PythonInstallation::find_best(
&request,
environment_preference,
python_preference,
&cache,
),
// For queries _other_ than a version, we fail as we would if `--python` were used.
// There's no backwards compatibility concern here because `-p` / `--python-version`
// was restricted to Python versions.
_ => 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 Down Expand Up @@ -227,6 +273,23 @@ pub(crate) async fn pip_compile(
}
}

if let Some(python_legacy) = python_legacy.as_ref() {
let request = PythonRequest::parse(&python_legacy);

// If the requested interpreter version does not match the interpreter we're using
if !no_build.is_none() && !request.satisfied(&interpreter, &cache) {
// Other cases should be unreachable, as we only use the legacy fallback for version
// requests
if let PythonRequest::Version(version) = request {
warn_user!(
"The requested Python version {} is not available; {} will be used to build dependencies instead.",
version,
interpreter.python_version(),
);
}
}
}

// Create the shared state.
let state = SharedState::default();

Expand Down
1 change: 1 addition & 0 deletions crates/uv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.settings.annotation_style,
args.settings.link_mode,
args.settings.python,
args.python_legacy,
args.settings.system,
globals.python_preference,
globals.concurrency,
Expand Down
3 changes: 3 additions & 0 deletions crates/uv/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1533,6 +1533,7 @@ pub(crate) struct PipCompileSettings {
pub(crate) overrides_from_workspace: Vec<Requirement>,
pub(crate) environments: SupportedEnvironments,
pub(crate) refresh: Refresh,
pub(crate) python_legacy: Option<String>,
pub(crate) settings: PipSettings,
}

Expand Down Expand Up @@ -1572,6 +1573,7 @@ impl PipCompileSettings {
no_binary,
only_binary,
python_version,
python_legacy,
python_platform,
universal,
no_universal,
Expand Down Expand Up @@ -1641,6 +1643,7 @@ impl PipCompileSettings {
overrides_from_workspace,
environments,
refresh: Refresh::from(refresh),
python_legacy,
settings: PipSettings::combine(
PipOptions {
python: python.and_then(Maybe::into_option),
Expand Down
Loading

0 comments on commit 16296d6

Please sign in to comment.