Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions crates/socket-patch-cli/tests/mode_migration_pypi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,145 @@ async fn uv_no_binary_is_refused_in_both_modes() {
}
}

/// #1603: `uv pip compile --no-binary six --format pylock.toml` records six
/// with only its sdist, and `uv pip` installs six only from an sdist under
/// that flag or a uv `no-binary` setting covering it, so the patched wheel
/// both modes wire fails the matching `uv pip sync`. Both used to wire it
/// and exit 0; they must refuse and write nothing. A flag naming another
/// package leaves the wheel installable.
#[tokio::test]
async fn uv_pylock_no_binary_is_refused_in_both_modes() {
let pylock = |flags: &str| {
format!(
"# This file was autogenerated by uv via the following command:\n\
# uv pip compile req.in{flags} --format pylock.toml -o pylock.toml\n\
lock-version = \"1.0\"\ncreated-by = \"uv\"\nrequires-python = \">=3.9\"\n\n\
[[packages]]\nname = \"six\"\nversion = \"1.16.0\"\n\
sdist = {{ url = \"https://files.pythonhosted.org/six-1.16.0.tar.gz\", \
hashes = {{ sha256 = \"{SDIST_SHA}\" }} }}\n\
wheels = [{{ url = \"https://files.pythonhosted.org/{WHEEL}\", \
hashes = {{ sha256 = \"{WHEEL_SHA}\" }} }}]\n"
)
};
let sdist_only = |flags: &str| {
let lock = pylock(flags);
let wheels = lock.find("wheels = ").unwrap();
lock[..wheels].to_string()
};
for (lock, config, refused) in [
(sdist_only(" --no-binary six"), None, true),
(sdist_only(" --no-binary :all:"), None, true),
(
pylock(""),
Some(("uv.toml", "[pip]\nno-binary = [\"six\"]\n")),
true,
),
(pylock(" --no-binary idna"), None, false),
] {
let label = format!("{config:?} {}", lock.lines().nth(1).unwrap());
let stage = |root: &Path| {
std::fs::write(root.join("pylock.toml"), &lock).unwrap();
if let Some((file, text)) = config {
std::fs::write(root.join(file), text).unwrap();
}
};
let (_tmp, root) = project();
stage(&root);
let before = tree(&root);
let server = MockServer::start().await;
mount_hosted_api(&server, true).await;
let (code, env) = hosted_scan(&root, &server);
assert_eq!(code, 0, "hosted {label}: {env:#}");
if refused {
assert_eq!(hosted_pinned(&env), 0, "hosted {label}: {env:#}");
assert!(
env.to_string().contains("redirect_uv_lock_unsupported")
&& env.to_string().contains("only from an sdist"),
"hosted {label}: {env:#}"
);
assert_eq!(tree(&root), before, "hosted {label} wrote nothing");
} else {
assert_eq!(hosted_pinned(&env), 1, "hosted {label}: {env:#}");
}

let (_tmp, root) = project();
stage(&root);
stage_manifest(&root);
let before = tree(&root);
let (code, env) = run_cli(&root, &["vendor"], &[]);
if refused {
assert_ne!(code, 0, "vendored {label}: {env:#}");
assert!(
env.to_string().contains("pypi_uv_no_binary"),
"vendored {label}: {env:#}"
);
assert_eq!(tree(&root), before, "vendored {label} wrote nothing");
} else {
assert_eq!(code, 0, "vendored {label}: {env:#}");
}
}
}

/// #1603: in a uv workspace member, `uv pip` reads the workspace root's
/// settings and never the member's own `[tool.uv]`, so a workspace-level
/// `no-binary-package` naming six makes the member's `uv pip sync` refuse
/// the patched wheel even though the member's pyproject (here holding only
/// `[tool.uv.sources]`) sets nothing. A run in a governed member is refused
/// whole in both modes (#1138) before any lock is read, so its pylock is
/// never wired.
#[tokio::test]
async fn uv_pylock_in_a_workspace_member_is_not_wired() {
let lock = format!(
"# This file was autogenerated by uv via the following command:\n\
# uv pip compile req.in --format pylock.toml -o pylock.toml\n\
lock-version = \"1.0\"\ncreated-by = \"uv\"\nrequires-python = \">=3.9\"\n\n\
[[packages]]\nname = \"six\"\nversion = \"1.16.0\"\n\
sdist = {{ url = \"https://files.pythonhosted.org/six-1.16.0.tar.gz\", \
hashes = {{ sha256 = \"{SDIST_SHA}\" }} }}\n\
wheels = [{{ url = \"https://files.pythonhosted.org/{WHEEL}\", \
hashes = {{ sha256 = \"{WHEEL_SHA}\" }} }}]\n"
);
let stage = |root: &Path| {
std::fs::write(
root.parent().unwrap().join("pyproject.toml"),
"[tool.uv.workspace]\nmembers = [\"proj\"]\n[tool.uv]\nno-binary-package = [\"six\"]\n",
)
.unwrap();
std::fs::write(
root.join("pyproject.toml"),
"[project]\nname = \"proj\"\nversion = \"0\"\n[tool.uv.sources]\nlib = { workspace = true }\n",
)
.unwrap();
std::fs::write(root.join("pylock.toml"), &lock).unwrap();
};

let (_tmp, root) = project();
stage(&root);
let before = tree(&root);
let server = MockServer::start().await;
mount_hosted_api(&server, true).await;
let (code, env) = hosted_scan(&root, &server);
assert_ne!(code, 0, "hosted: {env:#}");
assert!(
env.to_string()
.contains("redirect_workspace_lockfile_elsewhere"),
"hosted: {env:#}"
);
assert_eq!(tree(&root), before, "hosted wrote nothing");

let (_tmp, root) = project();
stage(&root);
stage_manifest(&root);
let before = tree(&root);
let (code, env) = run_cli(&root, &["vendor"], &[]);
assert_ne!(code, 0, "vendored: {env:#}");
assert!(
env.to_string().contains("pypi_uv_workspace_unsupported"),
"vendored: {env:#}"
);
assert_eq!(tree(&root), before, "vendored wrote nothing");
}

/// #1501: a PEP 723 script takes uv's settings from the nearest directory
/// at or above it that holds a `uv.toml` or a `pyproject.toml` with
/// `[tool.uv]`. A parent project's `no-sources = true` therefore drops the
Expand Down
16 changes: 11 additions & 5 deletions crates/socket-patch-core/src/hosted/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -709,16 +709,22 @@ pub async fn read_candidate_files(
.files
.keys()
.any(|path| path == "uv.lock" || crate::utils::python_lock::is_script_lock_name(path));
if uv_lane {
// A PEP 751 lock is installed with `uv pip`, which refuses the patched
// wheel under the `no-binary` settings of the root's `uv.toml` (#1603).
let pylock_lane = out
.files
.keys()
.any(|path| crate::utils::python_lock::is_pep751_lock_name(path));
if uv_lane || pylock_lane {
let rel = crate::utils::python_script::UV_TOML;
if let Some(text) = read_advisory(view, unreadable, rel).await {
out.files.insert(rel.to_string(), text);
}
}
// A PEP 723 script (#1501) or a project (#1545) also takes uv's
// settings from above the root when the root holds none; only a disk
// view has an above.
if uv_lane
// A PEP 723 script (#1501), a project (#1545) or `uv pip` installing a
// PEP 751 lock (#1603) also takes uv's settings from above the root
// when the root holds none; only a disk view has an above.
if (uv_lane || pylock_lane)
&& !crate::utils::python_script::root_governs_script(
out.files.get("pyproject.toml").map(String::as_str),
out.files
Expand Down
Loading
Loading