Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Respect tool.uv.environments in pip compile --universal #6663

Merged
merged 1 commit into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/pypi-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub use parsed_url::*;
pub use requirement::*;
pub use scheme::*;
pub use simple_json::*;
pub use supported_environments::*;

mod base_url;
mod direct_url;
Expand All @@ -17,3 +18,4 @@ mod parsed_url;
mod requirement;
mod scheme;
mod simple_json;
mod supported_environments;
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use serde::ser::SerializeSeq;

use pep508_rs::MarkerTree;

/// A list of supported marker environments.
#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub struct SupportedEnvironments(Vec<MarkerTree>);

Expand Down
6 changes: 4 additions & 2 deletions crates/uv-settings/src/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::path::PathBuf;

use distribution_types::IndexUrl;
use install_wheel_rs::linker::LinkMode;
use pypi_types::SupportedEnvironments;
use uv_configuration::{ConfigSettings, IndexStrategy, KeyringProviderType, TargetTriple};
use uv_python::{PythonDownloads, PythonPreference, PythonVersion};
use uv_resolver::{AnnotationStyle, ExcludeNewer, PrereleaseMode, ResolutionMode};
Expand Down Expand Up @@ -75,12 +76,13 @@ impl_combine_or!(LinkMode);
impl_combine_or!(NonZeroUsize);
impl_combine_or!(PathBuf);
impl_combine_or!(PrereleaseMode);
impl_combine_or!(PythonDownloads);
impl_combine_or!(PythonPreference);
impl_combine_or!(PythonVersion);
impl_combine_or!(ResolutionMode);
impl_combine_or!(String);
impl_combine_or!(SupportedEnvironments);
impl_combine_or!(TargetTriple);
impl_combine_or!(PythonPreference);
impl_combine_or!(PythonDownloads);
impl_combine_or!(bool);

impl<T> Combine for Option<Vec<T>> {
Expand Down
12 changes: 7 additions & 5 deletions crates/uv-settings/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
use distribution_types::{FlatIndexLocation, IndexUrl};
use install_wheel_rs::linker::LinkMode;
use pep508_rs::Requirement;
use pypi_types::VerbatimParsedUrl;
use pypi_types::{SupportedEnvironments, VerbatimParsedUrl};
use uv_configuration::{
ConfigSettings, IndexStrategy, KeyringProviderType, PackageNameSpecifier, TargetTriple,
};
Expand Down Expand Up @@ -43,9 +43,15 @@ pub struct Options {

// NOTE(charlie): These fields are shared with `ToolUv` in
// `crates/uv-workspace/src/pyproject.rs`, and the documentation lives on that struct.
#[cfg_attr(feature = "schemars", schemars(skip))]
pub override_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,

#[cfg_attr(feature = "schemars", schemars(skip))]
pub constraint_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,

#[cfg_attr(feature = "schemars", schemars(skip))]
pub environments: Option<SupportedEnvironments>,

// NOTE(charlie): These fields should be kept in-sync with `ToolUv` in
// `crates/uv-workspace/src/pyproject.rs`.
#[serde(default, skip_serializing)]
Expand All @@ -60,10 +66,6 @@ pub struct Options {
#[cfg_attr(feature = "schemars", schemars(skip))]
dev_dependencies: serde::de::IgnoredAny,

#[serde(default, skip_serializing)]
#[cfg_attr(feature = "schemars", schemars(skip))]
environments: serde::de::IgnoredAny,

#[serde(default, skip_serializing)]
#[cfg_attr(feature = "schemars", schemars(skip))]
managed: serde::de::IgnoredAny,
Expand Down
2 changes: 0 additions & 2 deletions crates/uv-workspace/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
pub use environments::SupportedEnvironments;
pub use workspace::{
check_nested_workspaces, DiscoveryOptions, ProjectWorkspace, VirtualProject, Workspace,
WorkspaceError, WorkspaceMember,
};

mod environments;
pub mod pyproject;
pub mod pyproject_mut;
mod workspace;
8 changes: 5 additions & 3 deletions crates/uv-workspace/src/pyproject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ use serde::{Deserialize, Serialize};
use thiserror::Error;
use url::Url;

use crate::environments::SupportedEnvironments;
use pep440_rs::VersionSpecifiers;
use pypi_types::{RequirementSource, VerbatimParsedUrl};
use pypi_types::{RequirementSource, SupportedEnvironments, VerbatimParsedUrl};
use uv_git::GitReference;
use uv_macros::OptionsMetadata;
use uv_normalize::{ExtraName, PackageName};
Expand Down Expand Up @@ -121,11 +120,14 @@ pub struct ToolUv {
/// By default, uv will resolve for all possible environments during a `uv lock` operation.
/// However, you can restrict the set of supported environments to improve performance and avoid
/// unsatisfiable branches in the solution space.
///
/// These environments will also respected when `uv pip compile` is invoked with the
/// `--universal` flag.
#[cfg_attr(
feature = "schemars",
schemars(
with = "Option<Vec<String>>",
description = "A list of environment markers, e.g. `python_version >= '3.6'`."
description = "A list of environment markers, e.g., `python_version >= '3.6'`."
)
)]
#[option(
Expand Down
3 changes: 1 addition & 2 deletions crates/uv-workspace/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ use rustc_hash::FxHashSet;
use tracing::{debug, trace, warn};

use pep508_rs::{MarkerTree, RequirementOrigin, VerbatimUrl};
use pypi_types::{Requirement, RequirementSource, VerbatimParsedUrl};
use pypi_types::{Requirement, RequirementSource, SupportedEnvironments, VerbatimParsedUrl};
use uv_fs::Simplified;
use uv_normalize::{GroupName, PackageName, DEV_DEPENDENCIES};
use uv_warnings::warn_user;

use crate::environments::SupportedEnvironments;
use crate::pyproject::{Project, PyProjectToml, Source, ToolUvWorkspace};

#[derive(thiserror::Error, Debug)]
Expand Down
14 changes: 9 additions & 5 deletions crates/uv/src/commands/pip/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use tracing::debug;

use distribution_types::{IndexLocations, UnresolvedRequirementSpecification, Verbatim};
use install_wheel_rs::linker::LinkMode;
use pypi_types::Requirement;
use pypi_types::{Requirement, SupportedEnvironments};
use uv_auth::store_credentials_from_url;
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
Expand Down Expand Up @@ -53,6 +53,7 @@ pub(crate) async fn pip_compile(
build_constraints: &[RequirementsSource],
constraints_from_workspace: Vec<Requirement>,
overrides_from_workspace: Vec<Requirement>,
environments: SupportedEnvironments,
extras: ExtrasSpecification,
output_file: Option<&Path>,
resolution_mode: ResolutionMode,
Expand Down Expand Up @@ -171,10 +172,10 @@ pub(crate) async fn pip_compile(
}

// Find an interpreter to use for building distributions
let environments = EnvironmentPreference::from_system_flag(system, false);
let environment_preference = EnvironmentPreference::from_system_flag(system, false);
let interpreter = if let Some(python) = python.as_ref() {
let request = PythonRequest::parse(python);
PythonInstallation::find(&request, environments, python_preference, &cache)
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.
Expand All @@ -184,7 +185,7 @@ pub(crate) async fn pip_compile(
} else {
PythonRequest::default()
};
PythonInstallation::find_best(&request, environments, python_preference, &cache)
PythonInstallation::find_best(&request, environment_preference, python_preference, &cache)
}?
.into_interpreter();

Expand Down Expand Up @@ -244,7 +245,10 @@ pub(crate) async fn pip_compile(

// Determine the environment for the resolution.
let (tags, markers) = if universal {
(None, ResolverMarkers::universal(vec![]))
(
None,
ResolverMarkers::universal(environments.into_markers()),
)
} else {
let (tags, markers) =
resolution_environment(python_version, python_platform, &interpreter)?;
Expand Down
4 changes: 2 additions & 2 deletions crates/uv/src/commands/project/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use tracing::debug;

use distribution_types::{IndexLocations, UnresolvedRequirementSpecification};
use pep440_rs::Version;
use pypi_types::Requirement;
use pypi_types::{Requirement, SupportedEnvironments};
use uv_auth::store_credentials_from_url;
use uv_cache::Cache;
use uv_client::{Connectivity, FlatIndexClient, RegistryClientBuilder};
Expand All @@ -28,7 +28,7 @@ use uv_resolver::{
};
use uv_types::{BuildContext, BuildIsolation, EmptyInstalledPackages, HashStrategy};
use uv_warnings::warn_user;
use uv_workspace::{DiscoveryOptions, SupportedEnvironments, Workspace};
use uv_workspace::{DiscoveryOptions, Workspace};

use crate::commands::pip::loggers::{DefaultResolveLogger, ResolveLogger, SummaryResolveLogger};
use crate::commands::project::{find_requires_python, FoundInterpreter, ProjectError, SharedState};
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 @@ -303,6 +303,7 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
&build_constraints,
args.constraints_from_workspace,
args.overrides_from_workspace,
args.environments,
args.settings.extras,
args.settings.output_file.as_deref(),
args.settings.resolution,
Expand Down
12 changes: 10 additions & 2 deletions crates/uv/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::str::FromStr;
use distribution_types::IndexLocations;
use install_wheel_rs::linker::LinkMode;
use pep508_rs::{ExtraName, RequirementOrigin};
use pypi_types::Requirement;
use pypi_types::{Requirement, SupportedEnvironments};
use uv_cache::{CacheArgs, Refresh};
use uv_cli::{
options::{flag, resolver_installer_options, resolver_options},
Expand Down Expand Up @@ -927,9 +927,10 @@ pub(crate) struct PipCompileSettings {
pub(crate) src_file: Vec<PathBuf>,
pub(crate) constraint: Vec<PathBuf>,
pub(crate) r#override: Vec<PathBuf>,
pub(crate) build_constraint: Vec<PathBuf>,
pub(crate) constraints_from_workspace: Vec<Requirement>,
pub(crate) overrides_from_workspace: Vec<Requirement>,
pub(crate) build_constraint: Vec<PathBuf>,
pub(crate) environments: SupportedEnvironments,
pub(crate) refresh: Refresh,
pub(crate) settings: PipSettings,
}
Expand Down Expand Up @@ -1015,6 +1016,12 @@ impl PipCompileSettings {
Vec::new()
};

let environments = if let Some(configuration) = &filesystem {
configuration.environments.clone().unwrap_or_default()
} else {
SupportedEnvironments::default()
};

Self {
src_file,
constraint: constraint
Expand All @@ -1031,6 +1038,7 @@ impl PipCompileSettings {
.collect(),
constraints_from_workspace,
overrides_from_workspace,
environments,
refresh: Refresh::from(refresh),
settings: PipSettings::combine(
PipOptions {
Expand Down
49 changes: 49 additions & 0 deletions crates/uv/tests/pip_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11946,3 +11946,52 @@ fn symlink() -> Result<()> {

Ok(())
}

/// Resolve with `--universal`, applying user-provided constraints to the space of supported
/// environments.
#[test]
fn universal_constrained_environment() -> Result<()> {
let context = TestContext::new("3.12");

let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["black"]

[tool.uv]
environments = "platform_system != 'Windows'"
"#,
)?;

uv_snapshot!(context.filters(), context.pip_compile()
.arg("pyproject.toml")
.arg("--universal"), @r###"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] pyproject.toml --universal
black==24.3.0 ; platform_system != 'Windows'
# via project (pyproject.toml)
click==8.1.7 ; platform_system != 'Windows'
# via black
mypy-extensions==1.0.0 ; platform_system != 'Windows'
# via black
packaging==24.0 ; platform_system != 'Windows'
# via black
pathspec==0.12.1 ; platform_system != 'Windows'
# via black
platformdirs==4.2.0 ; platform_system != 'Windows'
# via black

----- stderr -----
Resolved 6 packages in [TIME]
"###
);

Ok(())
}
Loading
Loading