Skip to content

Commit

Permalink
Respect tool.uv.environments in pip compile --universal (#6663)
Browse files Browse the repository at this point in the history
## Summary

We now respect the `environments` field in `uv pip compile --universal`,
e.g.:

```toml
[tool.uv]
environments = ["platform_system == 'Emscripten'"]
```

Closes #6641.
  • Loading branch information
charliermarsh authored Aug 26, 2024
1 parent 154ea24 commit 1ae2c3f
Show file tree
Hide file tree
Showing 15 changed files with 179 additions and 45 deletions.
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

0 comments on commit 1ae2c3f

Please sign in to comment.