Skip to content

Commit

Permalink
change: include in the result of uv pip compile that the dependency…
Browse files Browse the repository at this point in the history
… was overridden in the workspace configuration.
  • Loading branch information
Di-Is committed May 28, 2024
1 parent 7561375 commit 0948908
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 34 deletions.
15 changes: 12 additions & 3 deletions crates/distribution-types/src/annotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,22 @@ impl std::fmt::Display for SourceAnnotation {
RequirementOrigin::Project(path, project_name) => {
write!(f, "{project_name} ({})", path.portable_display())
}
RequirementOrigin::Workspace => panic!("Unsupported RequirementOrigin variant"),
},
Self::Constraint(origin) => {
write!(f, "-c {}", origin.path().portable_display())
}
Self::Override(origin) => {
write!(f, "--override {}", origin.path().portable_display())
}
Self::Override(origin) => match origin {
RequirementOrigin::File(path) => {
write!(f, "--override {}", path.portable_display())
}
RequirementOrigin::Workspace => {
write!(f, "--override (from workspace)")
}
RequirementOrigin::Project(_path, _project_name) => {
panic!("Unsupported RequirementOrigin variant")
}
},
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions crates/pep508-rs/src/origin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ pub enum RequirementOrigin {
File(PathBuf),
/// The requirement was provided via a local project (e.g., a `pyproject.toml` file).
Project(PathBuf, PackageName),
/// The requirement was provided via a workspace config file (e.g., a `pyproject.toml/uv.toml` file).
Workspace,
}

impl RequirementOrigin {
Expand All @@ -17,6 +19,7 @@ impl RequirementOrigin {
match self {
RequirementOrigin::File(path) => path.as_path(),
RequirementOrigin::Project(path, _) => path.as_path(),
_ => panic!("Unsupported RequirementOrigin variant"),
}
}
}
9 changes: 8 additions & 1 deletion crates/uv-requirements/src/sources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub enum RequirementsSource {
SetupCfg(PathBuf),
/// Dependencies were provided via a path to a source tree (e.g., `pip install .`).
SourceTree(PathBuf),
/// Dependencies were provided via a workspace config file (e.g. pyproject.toml/uv.toml).
WorkSpacePackage(String),
}

impl RequirementsSource {
Expand Down Expand Up @@ -124,6 +126,11 @@ impl RequirementsSource {
Self::Package(name)
}

/// Parse a [`RequirementsSource`] from a user-provided string, assumed to be a package in workspace config.
pub fn from_workspace_package(name: String) -> Self {
Self::WorkSpacePackage(Self::from_package(name).to_string())
}

/// Parse a [`RequirementsSource`] from a user-provided string, assumed to be a path to a source
/// tree.
pub fn from_source_tree(path: PathBuf) -> Self {
Expand All @@ -142,7 +149,7 @@ impl RequirementsSource {
impl std::fmt::Display for RequirementsSource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Package(package) => write!(f, "{package}"),
Self::Package(package) | Self::WorkSpacePackage(package) => write!(f, "{package}"),
Self::Editable(path) => write!(f, "-e {path}"),
Self::RequirementsTxt(path)
| Self::PyprojectToml(path)
Expand Down
14 changes: 14 additions & 0 deletions crates/uv-requirements/src/specification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,20 @@ impl RequirementsSpecification {
..Self::default()
}
}
RequirementsSource::WorkSpacePackage(name) => {
let requirement = RequirementsTxtRequirement::parse(name, std::env::current_dir()?)
.with_context(|| format!("Failed to parse: `{name}`"))?
.with_origin(pep508_rs::RequirementOrigin::Workspace);
Self {
requirements: vec![UnresolvedRequirementSpecification::from(
RequirementEntry {
requirement,
hashes: vec![],
},
)],
..Self::default()
}
}
RequirementsSource::Editable(name) => {
Self::from_editable_source(name, extras, workspace, preview).await?
}
Expand Down
12 changes: 2 additions & 10 deletions crates/uv/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,7 @@ async fn run() -> Result<ExitStatus> {
.r#override
.into_iter()
.map(RequirementsSource::from_overrides_txt)
.chain(
args.override_from_workspace
.into_iter()
.map(RequirementsSource::from_package),
)
.chain(args.override_from_workspace)
.collect::<Vec<_>>();

commands::pip_compile(
Expand Down Expand Up @@ -345,11 +341,7 @@ async fn run() -> Result<ExitStatus> {
.r#override
.into_iter()
.map(RequirementsSource::from_overrides_txt)
.chain(
args.override_from_workspace
.into_iter()
.map(RequirementsSource::from_package),
)
.chain(args.override_from_workspace)
.collect::<Vec<_>>();

commands::pip_install(
Expand Down
43 changes: 31 additions & 12 deletions crates/uv/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use uv_configuration::{
use uv_interpreter::{PythonVersion, Target};
use uv_normalize::PackageName;
use uv_requirements::ExtrasSpecification;
use uv_requirements::RequirementsSource;
use uv_resolver::{AnnotationStyle, DependencyMode, ExcludeNewer, PreReleaseMode, ResolutionMode};
use uv_workspace::{Combine, PipOptions, Workspace};

Expand Down Expand Up @@ -183,7 +184,7 @@ pub(crate) struct PipCompileSettings {
// Shared settings.
pub(crate) shared: PipSharedSettings,
// Override dependencies from workspace.
pub(crate) override_from_workspace: Vec<String>,
pub(crate) override_from_workspace: Vec<RequirementsSource>,
}

impl PipCompileSettings {
Expand Down Expand Up @@ -254,11 +255,20 @@ impl PipCompileSettings {
compat_args: _,
} = args;

let override_from_workspace: Vec<String> = workspace
.as_ref()
.and_then(|ws| ws.options.override_dependencies.as_ref())
.cloned()
.unwrap_or_else(Vec::new);
let override_from_workspace = if let Some(ws) = workspace.as_ref() {
ws.options
.override_dependencies
.as_ref()
.map_or_else(Vec::new, |deps| {
deps.iter()
.map(|name: &std::string::String| {
RequirementsSource::from_workspace_package(name.to_string())
})
.collect::<Vec<_>>()
})
} else {
Vec::new()
};

Self {
// CLI-only settings.
Expand Down Expand Up @@ -466,7 +476,7 @@ pub(crate) struct PipInstallSettings {
pub(crate) refresh: Refresh,
pub(crate) dry_run: bool,
pub(crate) uv_lock: Option<String>,
pub(crate) override_from_workspace: Vec<String>,
pub(crate) override_from_workspace: Vec<RequirementsSource>,

// Shared settings.
pub(crate) shared: PipSharedSettings,
Expand Down Expand Up @@ -534,11 +544,20 @@ impl PipInstallSettings {
compat_args: _,
} = args;

let override_from_workspace: Vec<String> = workspace
.as_ref()
.and_then(|ws| ws.options.override_dependencies.as_ref())
.cloned()
.unwrap_or_else(Vec::new);
let override_from_workspace = if let Some(ws) = workspace.as_ref() {
ws.options
.override_dependencies
.as_ref()
.map_or_else(Vec::new, |deps| {
deps.iter()
.map(|name: &std::string::String| {
RequirementsSource::from_workspace_package(name.to_string())
})
.collect::<Vec<_>>()
})
} else {
Vec::new()
};

Self {
// CLI-only settings.
Expand Down
86 changes: 78 additions & 8 deletions crates/uv/tests/pip_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2871,8 +2871,8 @@ fn override_dependency() -> Result<()> {
Ok(())
}

/// Flask==3.0.0 depends on Werkzeug>=3.0.0. Demonstrate that we can override this
/// requirement with an incompatible version using pyproject.toml.
/// Derived test for `override_dependency
/// Check if the configuration can be read from pyproject.toml.
#[test]
fn override_dependency_from_pyproject() -> Result<()> {
let context = TestContext::new("3.12");
Expand Down Expand Up @@ -2916,7 +2916,74 @@ fn override_dependency_from_pyproject() -> Result<()> {
# jinja2
# werkzeug
werkzeug==2.3.0
# via
# --override (from workspace)
# flask
----- stderr -----
Resolved 7 packages in [TIME]
"###
);

Ok(())
}

/// Derived test for `override_dependency
/// Check if the configuration can be read from uv.toml specified in the argument.
#[test]
fn override_dependency_from_specific_uvtoml() -> Result<()> {
let context = TestContext::new("3.12");
let _ = context.temp_dir.child("project").create_dir_all();
let pyproject_toml = context.temp_dir.child("project/pyproject.toml");
pyproject_toml.write_str(
r#"[project]
name = "example"
version = "0.0.0"
dependencies = [
"flask==3.0.0"
]
"#,
)?;

let _ = context.temp_dir.child("uv").create_dir_all();
let uv_toml: assert_fs::fixture::ChildPath = context.temp_dir.child("uv/uv.toml");
uv_toml.write_str(
r#"
override-dependencies = [
"werkzeug==2.3.0"
]
"#,
)?;

uv_snapshot!(context.compile()
.arg("pyproject.toml")
.arg("--config-file")
.arg("../uv/uv.toml")
.current_dir(&context.temp_dir.child("project"))
, @r###"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] --exclude-newer 2024-03-25T00:00:00Z pyproject.toml --config-file ../uv/uv.toml
blinker==1.7.0
# via flask
click==8.1.7
# via flask
flask==3.0.0
# via example (pyproject.toml)
itsdangerous==2.1.2
# via flask
jinja2==3.1.3
# via flask
markupsafe==2.1.5
# via
# jinja2
# werkzeug
werkzeug==2.3.0
# via
# --override (from workspace)
# flask
----- stderr -----
Resolved 7 packages in [TIME]
Expand All @@ -2926,12 +2993,13 @@ fn override_dependency_from_pyproject() -> Result<()> {
Ok(())
}

/// Flask==3.0.0 depends on Werkzeug>=3.0.0. Demonstrate that we can override this
/// requirement with an incompatible version using uv.toml.
/// Derivation test of `override_dependency
/// Check if the configuration can be read from uv.toml in workspace.
#[test]
fn override_dependency_from_uvtoml() -> Result<()> {
fn override_dependency_from_workspace_uvtoml() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
let _ = context.temp_dir.child("sample").create_dir_all();
let pyproject_toml = context.temp_dir.child("sample/pyproject.toml");
pyproject_toml.write_str(
r#"[project]
name = "example"
Expand All @@ -2953,7 +3021,7 @@ fn override_dependency_from_uvtoml() -> Result<()> {

uv_snapshot!(context.compile()
.arg("pyproject.toml")
.current_dir(&context.temp_dir)
.current_dir(&context.temp_dir.child("sample"))
, @r###"
success: true
exit_code: 0
Expand All @@ -2975,7 +3043,9 @@ fn override_dependency_from_uvtoml() -> Result<()> {
# jinja2
# werkzeug
werkzeug==2.3.0
# via flask
# via
# --override (from workspace)
# flask
----- stderr -----
Resolved 7 packages in [TIME]
Expand Down
9 changes: 9 additions & 0 deletions uv.schema.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 0948908

Please sign in to comment.