mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-04 19:08:04 +00:00
Drop trailing slashes when converting index URL from URL (#14346)
## Summary In #14245, we started normalizing index URLs by dropping the trailing slash in the lockfile. We added tests to ensure that this didn't cause existing lockfiles to be invalidated, but we missed one of the constructors (specifically, the path that's used with `tool.uv.sources`).
This commit is contained in:
parent
f9d3f8ea3b
commit
734b228edf
3 changed files with 201 additions and 15 deletions
|
@ -44,16 +44,9 @@ impl IndexUrl {
|
|||
let url = match split_scheme(path) {
|
||||
Some((scheme, ..)) => {
|
||||
match Scheme::parse(scheme) {
|
||||
Some(scheme) => {
|
||||
if scheme.is_file() {
|
||||
// Ex) `file:///path/to/something/`
|
||||
Some(_) => {
|
||||
// Ex) `https://pypi.org/simple`
|
||||
VerbatimUrl::parse_url(path)?
|
||||
} else {
|
||||
// Ex) `https://pypi.org/simple/`
|
||||
// Remove a trailing slash if it exists.
|
||||
let normalized_path = path.strip_suffix('/').unwrap_or(path);
|
||||
VerbatimUrl::parse_url(normalized_path)?
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// Ex) `C:\Users\user\index`
|
||||
|
@ -265,15 +258,22 @@ impl<'de> serde::de::Deserialize<'de> for IndexUrl {
|
|||
}
|
||||
|
||||
impl From<VerbatimUrl> for IndexUrl {
|
||||
fn from(url: VerbatimUrl) -> Self {
|
||||
fn from(mut url: VerbatimUrl) -> Self {
|
||||
if url.scheme() == "file" {
|
||||
Self::Path(Arc::new(url))
|
||||
} else if *url.raw() == *PYPI_URL {
|
||||
} else {
|
||||
// Remove trailing slashes for consistency. They'll be re-added if necessary when
|
||||
// querying the Simple API.
|
||||
if let Ok(mut path_segments) = url.raw_mut().path_segments_mut() {
|
||||
path_segments.pop_if_empty();
|
||||
}
|
||||
if *url.raw() == *PYPI_URL {
|
||||
Self::Pypi(Arc::new(url))
|
||||
} else {
|
||||
Self::Url(Arc::new(url))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IndexUrl> for DisplaySafeUrl {
|
||||
|
|
|
@ -166,6 +166,11 @@ impl VerbatimUrl {
|
|||
&self.url
|
||||
}
|
||||
|
||||
/// Return a mutable reference to the underlying [`DisplaySafeUrl`].
|
||||
pub fn raw_mut(&mut self) -> &mut DisplaySafeUrl {
|
||||
&mut self.url
|
||||
}
|
||||
|
||||
/// Convert a [`VerbatimUrl`] into a [`DisplaySafeUrl`].
|
||||
pub fn to_url(&self) -> DisplaySafeUrl {
|
||||
self.url.clone()
|
||||
|
|
|
@ -28448,6 +28448,9 @@ fn lock_with_index_trailing_slashes_in_lockfile() -> Result<()> {
|
|||
[[tool.uv.index]]
|
||||
name = "pypi-proxy"
|
||||
url = "https://pypi-proxy.fly.dev/simple"
|
||||
|
||||
[tool.uv.sources]
|
||||
anyio = { index = "pypi-proxy" }
|
||||
"#,
|
||||
)?;
|
||||
|
||||
|
@ -28491,7 +28494,185 @@ fn lock_with_index_trailing_slashes_in_lockfile() -> Result<()> {
|
|||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "anyio" }]
|
||||
requires-dist = [{ name = "anyio", index = "https://pypi-proxy.fly.dev/simple/" }]
|
||||
|
||||
[[package]]
|
||||
name = "sniffio"
|
||||
version = "1.3.1"
|
||||
source = { registry = "https://pypi-proxy.fly.dev/simple/" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
|
||||
]
|
||||
"#
|
||||
)?;
|
||||
|
||||
// Run `uv lock --locked`.
|
||||
uv_snapshot!(context.filters(), context.lock().arg("--locked"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 4 packages in [TIME]
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Run `uv lock --locked` with a lockfile with trailing slashes on index URLs.
|
||||
#[test]
|
||||
fn lock_with_index_trailing_slashes_in_pyproject_toml() -> 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 = ["anyio"]
|
||||
|
||||
[[tool.uv.index]]
|
||||
name = "pypi-proxy"
|
||||
url = "https://pypi-proxy.fly.dev/simple/"
|
||||
|
||||
[tool.uv.sources]
|
||||
anyio = { index = "pypi-proxy" }
|
||||
"#,
|
||||
)?;
|
||||
|
||||
let lock = context.temp_dir.child("uv.lock");
|
||||
lock.write_str(r#"
|
||||
version = 1
|
||||
revision = 2
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[options]
|
||||
exclude-newer = "2024-03-25T00:00:00Z"
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "4.3.0"
|
||||
source = { registry = "https://pypi-proxy.fly.dev/simple" }
|
||||
dependencies = [
|
||||
{ name = "idna" },
|
||||
{ name = "sniffio" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6", size = 159642, upload-time = "2024-02-19T08:36:28.641Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8", size = 85584, upload-time = "2024-02-19T08:36:26.842Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.6"
|
||||
source = { registry = "https://pypi-proxy.fly.dev/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/bf/3f/ea4b9117521a1e9c50344b909be7886dd00a519552724809bb1f486986c2/idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", size = 175426, upload-time = "2023-11-25T15:40:54.902Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/e7/a82b05cf63a603df6e68d59ae6a68bf5064484a0718ea5033660af4b54a9/idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f", size = 61567, upload-time = "2023-11-25T15:40:52.604Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "anyio", index = "https://pypi-proxy.fly.dev/simple" }]
|
||||
|
||||
[[package]]
|
||||
name = "sniffio"
|
||||
version = "1.3.1"
|
||||
source = { registry = "https://pypi-proxy.fly.dev/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
|
||||
]
|
||||
"#
|
||||
)?;
|
||||
|
||||
// Run `uv lock --locked`.
|
||||
uv_snapshot!(context.filters(), context.lock().arg("--locked"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 4 packages in [TIME]
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Run `uv lock --locked` with a lockfile with trailing slashes on index URLs.
|
||||
#[test]
|
||||
fn lock_with_index_trailing_slashes_in_lockfile_and_pyproject_toml() -> 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 = ["anyio"]
|
||||
|
||||
[[tool.uv.index]]
|
||||
name = "pypi-proxy"
|
||||
url = "https://pypi-proxy.fly.dev/simple/"
|
||||
|
||||
[tool.uv.sources]
|
||||
anyio = { index = "pypi-proxy" }
|
||||
"#,
|
||||
)?;
|
||||
|
||||
let lock = context.temp_dir.child("uv.lock");
|
||||
lock.write_str(r#"
|
||||
version = 1
|
||||
revision = 2
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[options]
|
||||
exclude-newer = "2024-03-25T00:00:00Z"
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "4.3.0"
|
||||
source = { registry = "https://pypi-proxy.fly.dev/simple/" }
|
||||
dependencies = [
|
||||
{ name = "idna" },
|
||||
{ name = "sniffio" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6", size = 159642, upload-time = "2024-02-19T08:36:28.641Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8", size = 85584, upload-time = "2024-02-19T08:36:26.842Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.6"
|
||||
source = { registry = "https://pypi-proxy.fly.dev/simple/" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/bf/3f/ea4b9117521a1e9c50344b909be7886dd00a519552724809bb1f486986c2/idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", size = 175426, upload-time = "2023-11-25T15:40:54.902Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/e7/a82b05cf63a603df6e68d59ae6a68bf5064484a0718ea5033660af4b54a9/idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f", size = 61567, upload-time = "2023-11-25T15:40:52.604Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "anyio", index = "https://pypi-proxy.fly.dev/simple/" }]
|
||||
|
||||
[[package]]
|
||||
name = "sniffio"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue