Skip to content

Commit 887a5f7

Browse files
Fix Pipenv requirements remedy categories (#1507) (#1508)
* Start fix for #1507 Assisted-by: Claude Code:claude-opus-5-5 * Fix empty Pipenv export in base-interpreter fix The remedy for a stale base-interpreter copy in a --site-packages venv printed `pipenv requirements --categories "packages docs"` when the package sat in several lock categories, one of them named. Pipenv 2022.12.x-2023.2.4 read that as one category the lock lacks, so the export was empty, pip exited 0 and the venv kept importing the unpatched copy while the warning repeated. The export now names comma-joined lock keys ("default,docs"), which every Pipenv release with --categories reads. The sync remedies keep the Pipfile names `pipenv sync` takes. Fixes #1507 Assisted-by: Claude Code:claude-opus-5-5 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent e467944 commit 887a5f7

2 files changed

Lines changed: 83 additions & 5 deletions

File tree

‎crates/socket-patch-core/src/vendor/pypi_pipenv.rs‎

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,21 @@ fn sync_args(sections: &[&str]) -> String {
760760
}
761761
}
762762

763+
/// The `pipenv requirements` arguments that export every lock section in
764+
/// `sections`. Plain `requirements` exports `default` and `--dev` adds
765+
/// `develop`, as for `sync`, but its `--categories` differs: Pipenv
766+
/// 2022.12–2023.2.4 split it on commas and look each name up as a lock
767+
/// key, so `sync`'s space-joined Pipfile names (`"packages docs"`) export
768+
/// nothing (#1507). Comma-joined lock keys (`"default,docs"`) work on
769+
/// every release that has `--categories`.
770+
fn requirements_args(sections: &[&str]) -> String {
771+
if sections.iter().all(|s| *s == "default" || *s == "develop") {
772+
sync_args(sections)
773+
} else {
774+
format!(" --categories \"{}\"", sections.join(","))
775+
}
776+
}
777+
763778
/// `default`, then `develop`, then named categories in lock order — so the
764779
/// rendered `--categories` list is stable.
765780
fn ordered_sections(mut sections: Vec<&str>) -> Vec<&str> {
@@ -872,7 +887,7 @@ pub fn shadowing_stale_install_remedy(
872887
/// The install-over command both base-interpreter remedies share.
873888
fn install_over_command(lock: Option<&Value>, name: &str) -> String {
874889
let (package, _) = lock_sections(lock, name);
875-
let categories = sync_args(&package);
890+
let categories = requirements_args(&package);
876891
// `pipenv requirements` arrived in 2022.4; its `--categories` later
877892
// (present in 2022.12).
878893
let since = if categories.starts_with(" --categories") {
@@ -2389,11 +2404,71 @@ mod tests {
23892404
));
23902405
let remedy = base_site_stale_install_remedy(Some(&named), "six", dir);
23912406
assert!(
2392-
remedy.contains("`pipenv requirements --categories \"packages docs\" > "),
2407+
remedy.contains("`pipenv requirements --categories \"default,docs\" > "),
23932408
"{remedy}"
23942409
);
23952410
assert!(remedy.contains("(Pipenv 2022.12+;"), "{remedy}");
23962411
let remedy = base_site_stale_install_remedy(None, "six", dir);
23972412
assert!(remedy.contains("`pipenv requirements > "), "{remedy}");
23982413
}
2414+
2415+
/// #1507: Pipenv 2022.12.x–2023.2.4 `requirements` split `--categories`
2416+
/// on commas and look each name up as a lock key, so the space-joined
2417+
/// Pipfile names `sync` takes (`"packages docs"`) export nothing. The
2418+
/// export spells comma-joined lock keys, which every release reads,
2419+
/// while the sync remedies keep the Pipfile names.
2420+
#[test]
2421+
fn base_site_remedy_exports_comma_joined_lock_keys() {
2422+
let lock = |body: &str| -> Value {
2423+
serde_json::from_str(&format!(r#"{{"_meta": {{"pipfile-spec": 6}}, {body}}}"#)).unwrap()
2424+
};
2425+
let six = r#"{"version": "==1.16.0"}"#;
2426+
let dir = "/usr/lib/python3/dist-packages";
2427+
for (body, export) in [
2428+
(
2429+
format!(r#""default": {{"idna": {six}, "six": {six}}}, "docs": {{"six": {six}}}"#),
2430+
"--categories \"default,docs\"",
2431+
),
2432+
(
2433+
format!(
2434+
r#""default": {{"idna": {six}}}, "develop": {{"six": {six}}}, "docs": {{"six": {six}}}"#
2435+
),
2436+
"--categories \"develop,docs\"",
2437+
),
2438+
(
2439+
format!(
2440+
r#""default": {{"six": {six}}}, "develop": {{"six": {six}}}, "docs": {{"six": {six}}}, "tests": {{"six": {six}}}"#
2441+
),
2442+
"--categories \"default,develop,docs,tests\"",
2443+
),
2444+
(
2445+
format!(r#""default": {{"idna": {six}}}, "docs": {{"six": {six}}}"#),
2446+
"--categories \"docs\"",
2447+
),
2448+
] {
2449+
let lock = lock(&body);
2450+
for remedy in [
2451+
base_site_stale_install_remedy(Some(&lock), "six", dir),
2452+
shadowing_stale_install_remedy(Some(&lock), "six", dir, dir),
2453+
] {
2454+
assert!(
2455+
remedy.contains(&format!("`pipenv requirements {export} > ")),
2456+
"{export}: {remedy}"
2457+
);
2458+
for pipfile_name in ["packages docs", "dev-packages"] {
2459+
assert!(!remedy.contains(pipfile_name), "{remedy}");
2460+
}
2461+
assert!(remedy.contains("(Pipenv 2022.12+;"), "{remedy}");
2462+
}
2463+
}
2464+
// `sync` still takes the Pipfile names.
2465+
let named = lock(&format!(
2466+
r#""default": {{"six": {six}}}, "docs": {{"six": {six}}}"#
2467+
));
2468+
let remedy = stale_install_remedy(Some(&named), "six");
2469+
assert!(
2470+
remedy.contains("pipenv sync --categories \"packages docs\"`"),
2471+
"{remedy}"
2472+
);
2473+
}
23992474
}

‎docs/testing/pipenv-compatibility.md‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,12 @@ import on modern Pythons); 2018–2022 on Python 3.8; 2023+ on Python 3.12.
6464
venv, counts it as installed, so the lock protects no install on that
6565
host. For a stale copy there the warning instead prints `pipenv
6666
requirements > pipenv-locked.txt && pipenv run pip install --no-deps
67-
--ignore-installed -r pipenv-locked.txt` (Pipenv 2022.4+, with the same
68-
category arguments), which installs the locked release inside the venv
69-
and leaves the base copy untouched (#1450).
67+
--ignore-installed -r pipenv-locked.txt` (Pipenv 2022.4+), which installs
68+
the locked release inside the venv and leaves the base copy untouched
69+
(#1450). The export takes `--dev` like `sync`, but names categories as
70+
comma-joined lock keys (`--categories "default,docs"`, Pipenv 2022.12+):
71+
2022.12.x–2023.2.4 split the list on commas and look each name up in the
72+
lock, so `sync`'s `"packages docs"` exports nothing there (#1507).
7073
- **Relocking drops the reference.** `pipenv lock` (and `update`, and
7174
`install <other>` on releases before 2024, where it is a full relock)
7275
regenerates the redirected entry to its registry reference on every major,

0 commit comments

Comments
 (0)