mirror of https://github.com/astral-sh/uv
Allow transitive URLs via recursive extras (#4155)
## Summary Closes https://github.com/astral-sh/uv/issues/4152.
This commit is contained in:
parent
c46fa74e65
commit
ac1ddf5e4e
|
|
@ -141,38 +141,11 @@ impl<'a, Context: BuildContext> LookaheadResolver<'a, Context> {
|
||||||
requirement: Requirement,
|
requirement: Requirement,
|
||||||
) -> Result<Option<RequestedRequirements>, LookaheadError> {
|
) -> Result<Option<RequestedRequirements>, LookaheadError> {
|
||||||
trace!("Performing lookahead for {requirement}");
|
trace!("Performing lookahead for {requirement}");
|
||||||
|
|
||||||
// Determine whether the requirement represents a local distribution and convert to a
|
// Determine whether the requirement represents a local distribution and convert to a
|
||||||
// buildable distribution.
|
// buildable distribution.
|
||||||
let dist = match requirement.source {
|
let Some(dist) = required_dist(&requirement)? else {
|
||||||
RequirementSource::Registry { .. } => return Ok(None),
|
return Ok(None);
|
||||||
RequirementSource::Url {
|
|
||||||
subdirectory,
|
|
||||||
location,
|
|
||||||
url,
|
|
||||||
} => Dist::from_http_url(requirement.name, url, location, subdirectory)?,
|
|
||||||
RequirementSource::Git {
|
|
||||||
repository,
|
|
||||||
reference,
|
|
||||||
precise,
|
|
||||||
subdirectory,
|
|
||||||
url,
|
|
||||||
} => {
|
|
||||||
let mut git_url = GitUrl::new(repository, reference);
|
|
||||||
if let Some(precise) = precise {
|
|
||||||
git_url = git_url.with_precise(precise);
|
|
||||||
}
|
|
||||||
Dist::Source(SourceDist::Git(GitSourceDist {
|
|
||||||
name: requirement.name,
|
|
||||||
git: Box::new(git_url),
|
|
||||||
subdirectory,
|
|
||||||
url,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
RequirementSource::Path {
|
|
||||||
path,
|
|
||||||
url,
|
|
||||||
editable,
|
|
||||||
} => Dist::from_file_url(requirement.name, url, &path, editable)?,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fetch the metadata for the distribution.
|
// Fetch the metadata for the distribution.
|
||||||
|
|
@ -217,6 +190,21 @@ impl<'a, Context: BuildContext> LookaheadResolver<'a, Context> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Respect recursive extras by propagating the source extras to the dependencies.
|
||||||
|
let requires_dist = requires_dist
|
||||||
|
.into_iter()
|
||||||
|
.map(|dependency| {
|
||||||
|
if dependency.name == requirement.name {
|
||||||
|
Requirement {
|
||||||
|
source: requirement.source.clone(),
|
||||||
|
..dependency
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dependency
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
// Consider the dependencies to be "direct" if the requirement is a local source tree.
|
// Consider the dependencies to be "direct" if the requirement is a local source tree.
|
||||||
let direct = if let Dist::Source(source_dist) = &dist {
|
let direct = if let Dist::Source(source_dist) = &dist {
|
||||||
source_dist.as_path().is_some_and(std::path::Path::is_dir)
|
source_dist.as_path().is_some_and(std::path::Path::is_dir)
|
||||||
|
|
@ -232,3 +220,43 @@ impl<'a, Context: BuildContext> LookaheadResolver<'a, Context> {
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert a [`Requirement`] into a [`Dist`], if it is a direct URL.
|
||||||
|
fn required_dist(requirement: &Requirement) -> Result<Option<Dist>, distribution_types::Error> {
|
||||||
|
Ok(Some(match &requirement.source {
|
||||||
|
RequirementSource::Registry { .. } => return Ok(None),
|
||||||
|
RequirementSource::Url {
|
||||||
|
subdirectory,
|
||||||
|
location,
|
||||||
|
url,
|
||||||
|
} => Dist::from_http_url(
|
||||||
|
requirement.name.clone(),
|
||||||
|
url.clone(),
|
||||||
|
location.clone(),
|
||||||
|
subdirectory.clone(),
|
||||||
|
)?,
|
||||||
|
RequirementSource::Git {
|
||||||
|
repository,
|
||||||
|
reference,
|
||||||
|
precise,
|
||||||
|
subdirectory,
|
||||||
|
url,
|
||||||
|
} => {
|
||||||
|
let mut git_url = GitUrl::new(repository.clone(), reference.clone());
|
||||||
|
if let Some(precise) = precise {
|
||||||
|
git_url = git_url.with_precise(*precise);
|
||||||
|
}
|
||||||
|
Dist::Source(SourceDist::Git(GitSourceDist {
|
||||||
|
name: requirement.name.clone(),
|
||||||
|
git: Box::new(git_url),
|
||||||
|
subdirectory: subdirectory.clone(),
|
||||||
|
url: url.clone(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
RequirementSource::Path {
|
||||||
|
path,
|
||||||
|
url,
|
||||||
|
editable,
|
||||||
|
} => Dist::from_file_url(requirement.name.clone(), url.clone(), path, *editable)?,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5211,3 +5211,41 @@ fn tool_uv_sources_is_in_preview() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allow transitive URLs via recursive extras.
|
||||||
|
#[test]
|
||||||
|
fn recursive_extra_transitive_url() -> Result<()> {
|
||||||
|
let context = TestContext::new("3.12");
|
||||||
|
|
||||||
|
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||||
|
pyproject_toml.write_str(indoc! {r#"
|
||||||
|
[project]
|
||||||
|
name = "project"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = []
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
all = [
|
||||||
|
"project[docs]",
|
||||||
|
]
|
||||||
|
docs = [
|
||||||
|
"iniconfig @ https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl",
|
||||||
|
]
|
||||||
|
"#})?;
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context.install()
|
||||||
|
.arg(".[all]"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Resolved 2 packages in [TIME]
|
||||||
|
Downloaded 2 packages in [TIME]
|
||||||
|
Installed 2 packages in [TIME]
|
||||||
|
+ iniconfig==2.0.0 (from https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl)
|
||||||
|
+ project==0.0.0 (from file://[TEMP_DIR]/)
|
||||||
|
"###);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue