Only write portable paths in RECORD (#17339)

The spec allows both, but we're already using forward paths for paths
that are not created by uv.

See
* https://github.com/astral-sh/uv/issues/14446
* https://github.com/python/importlib_metadata/issues/528

Closes #14446

---------

Co-authored-by: Tomasz Kramkowski <tom@astral.sh>
This commit is contained in:
konsti
2026-01-07 20:40:18 +01:00
committed by GitHub
parent c71ba13b6d
commit 6b2d6f2c40
3 changed files with 67 additions and 3 deletions

View File

@@ -373,7 +373,9 @@ pub(crate) fn move_folder_recorded(
src.simplified_display()
))
})?;
entry.path = relative_to(&target, site_packages)?.display().to_string();
entry.path = relative_to(&target, site_packages)?
.portable_display()
.to_string();
}
}
Ok(())
@@ -576,7 +578,7 @@ fn install_script(
})?;
// Update the entry in the `RECORD`.
entry.path = script_relative.simplified_display().to_string();
entry.path = script_relative.portable_display().to_string();
if let Some((size, encoded_hash)) = size_and_encoded_hash {
entry.size = Some(size);
entry.hash = Some(encoded_hash);

View File

@@ -13660,3 +13660,65 @@ fn build_backend_wrong_wheel_platform() -> Result<()> {
Ok(())
}
/// Test that RECORD entries use forward slashes on all platforms.
///
/// See <https://github.com/astral-sh/uv/issues/14446>.
#[test]
fn record_uses_forward_slashes() -> Result<()> {
let context = TestContext::new("3.12");
// Create a package with scripts via uv_build data directory.
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(indoc! {r#"
[project]
name = "project"
version = "0.1.0"
[build-system]
requires = ["uv_build>=0.7,<10000"]
build-backend = "uv_build"
[tool.uv.build-backend.data]
scripts = "scripts"
headers = "headers"
"#})?;
let module_dir = context.temp_dir.child("src").child("project");
module_dir.child("__init__.py").touch()?;
// Create a script that uses the install_script path.
let scripts_dir = context.temp_dir.child("scripts");
scripts_dir.child("my_script").write_str(indoc! {r#"
#!python
print("Hello from script")
"#})?;
let scripts_dir = context.temp_dir.child("headers");
scripts_dir.child("project.h").write_str(indoc! {r"
#include <stdio.h>
"})?;
context.pip_install().arg(".").assert().success();
// Read the RECORD file and check that all paths use forward slashes.
let record_path = context
.site_packages()
.join("project-0.1.0.dist-info")
.join("RECORD");
let record = fs::read_to_string(&record_path)?;
let record_lines: Vec<_> = record
.lines()
.filter(|line| !line.trim().is_empty())
.collect();
assert!(record_lines.iter().any(|line| line.contains("/my_script")));
assert!(record_lines.iter().any(|line| line.contains("/project.h")));
for line in record_lines {
// Each RECORD line is: path,hash,size
let path = line.split(',').next().unwrap();
assert!(!path.contains('\\'), "{path}");
}
Ok(())
}

View File

@@ -3147,9 +3147,9 @@ fn tool_run_windows_runnable_types() -> anyhow::Result<()> {
----- stderr -----
An executable named `does_not_exist` is not provided by package `foo`.
The following executables are available:
- custom_pydoc.exe
- custom_pydoc.bat
- custom_pydoc.cmd
- custom_pydoc.exe
- custom_pydoc.ps1
"###);