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
79 changes: 77 additions & 2 deletions crates/socket-patch-core/src/vendor/pypi_pipenv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,21 @@ fn sync_args(sections: &[&str]) -> String {
}
}

/// The `pipenv requirements` arguments that export every lock section in
/// `sections`. Plain `requirements` exports `default` and `--dev` adds
/// `develop`, as for `sync`, but its `--categories` differs: Pipenv
/// 2022.12–2023.2.4 split it on commas and look each name up as a lock
/// key, so `sync`'s space-joined Pipfile names (`"packages docs"`) export
/// nothing (#1507). Comma-joined lock keys (`"default,docs"`) work on
/// every release that has `--categories`.
fn requirements_args(sections: &[&str]) -> String {
if sections.iter().all(|s| *s == "default" || *s == "develop") {
sync_args(sections)
} else {
format!(" --categories \"{}\"", sections.join(","))
}
}

/// `default`, then `develop`, then named categories in lock order — so the
/// rendered `--categories` list is stable.
fn ordered_sections(mut sections: Vec<&str>) -> Vec<&str> {
Expand Down Expand Up @@ -872,7 +887,7 @@ pub fn shadowing_stale_install_remedy(
/// The install-over command both base-interpreter remedies share.
fn install_over_command(lock: Option<&Value>, name: &str) -> String {
let (package, _) = lock_sections(lock, name);
let categories = sync_args(&package);
let categories = requirements_args(&package);
// `pipenv requirements` arrived in 2022.4; its `--categories` later
// (present in 2022.12).
let since = if categories.starts_with(" --categories") {
Expand Down Expand Up @@ -2389,11 +2404,71 @@ mod tests {
));
let remedy = base_site_stale_install_remedy(Some(&named), "six", dir);
assert!(
remedy.contains("`pipenv requirements --categories \"packages docs\" > "),
remedy.contains("`pipenv requirements --categories \"default,docs\" > "),
"{remedy}"
);
assert!(remedy.contains("(Pipenv 2022.12+;"), "{remedy}");
let remedy = base_site_stale_install_remedy(None, "six", dir);
assert!(remedy.contains("`pipenv requirements > "), "{remedy}");
}

/// #1507: Pipenv 2022.12.x–2023.2.4 `requirements` split `--categories`
/// on commas and look each name up as a lock key, so the space-joined
/// Pipfile names `sync` takes (`"packages docs"`) export nothing. The
/// export spells comma-joined lock keys, which every release reads,
/// while the sync remedies keep the Pipfile names.
#[test]
fn base_site_remedy_exports_comma_joined_lock_keys() {
let lock = |body: &str| -> Value {
serde_json::from_str(&format!(r#"{{"_meta": {{"pipfile-spec": 6}}, {body}}}"#)).unwrap()
};
let six = r#"{"version": "==1.16.0"}"#;
let dir = "/usr/lib/python3/dist-packages";
for (body, export) in [
(
format!(r#""default": {{"idna": {six}, "six": {six}}}, "docs": {{"six": {six}}}"#),
"--categories \"default,docs\"",
),
(
format!(
r#""default": {{"idna": {six}}}, "develop": {{"six": {six}}}, "docs": {{"six": {six}}}"#
),
"--categories \"develop,docs\"",
),
(
format!(
r#""default": {{"six": {six}}}, "develop": {{"six": {six}}}, "docs": {{"six": {six}}}, "tests": {{"six": {six}}}"#
),
"--categories \"default,develop,docs,tests\"",
),
(
format!(r#""default": {{"idna": {six}}}, "docs": {{"six": {six}}}"#),
"--categories \"docs\"",
),
] {
let lock = lock(&body);
for remedy in [
base_site_stale_install_remedy(Some(&lock), "six", dir),
shadowing_stale_install_remedy(Some(&lock), "six", dir, dir),
] {
assert!(
remedy.contains(&format!("`pipenv requirements {export} > ")),
"{export}: {remedy}"
);
for pipfile_name in ["packages docs", "dev-packages"] {
assert!(!remedy.contains(pipfile_name), "{remedy}");
}
assert!(remedy.contains("(Pipenv 2022.12+;"), "{remedy}");
}
}
// `sync` still takes the Pipfile names.
let named = lock(&format!(
r#""default": {{"six": {six}}}, "docs": {{"six": {six}}}"#
));
let remedy = stale_install_remedy(Some(&named), "six");
assert!(
remedy.contains("pipenv sync --categories \"packages docs\"`"),
"{remedy}"
);
}
}
9 changes: 6 additions & 3 deletions docs/testing/pipenv-compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,12 @@ import on modern Pythons); 2018–2022 on Python 3.8; 2023+ on Python 3.12.
venv, counts it as installed, so the lock protects no install on that
host. For a stale copy there the warning instead prints `pipenv
requirements > pipenv-locked.txt && pipenv run pip install --no-deps
--ignore-installed -r pipenv-locked.txt` (Pipenv 2022.4+, with the same
category arguments), which installs the locked release inside the venv
and leaves the base copy untouched (#1450).
--ignore-installed -r pipenv-locked.txt` (Pipenv 2022.4+), which installs
the locked release inside the venv and leaves the base copy untouched
(#1450). The export takes `--dev` like `sync`, but names categories as
comma-joined lock keys (`--categories "default,docs"`, Pipenv 2022.12+):
2022.12.x–2023.2.4 split the list on commas and look each name up in the
lock, so `sync`'s `"packages docs"` exports nothing there (#1507).
- **Relocking drops the reference.** `pipenv lock` (and `update`, and
`install <other>` on releases before 2024, where it is a full relock)
regenerates the redirected entry to its registry reference on every major,
Expand Down
Loading