Future-proof pip entrypoints special case (#1982)

Update #1918 to handle https://github.com/pypa/pip/pull/12536, where pip
removed their python minor entrypoint. The pip test is semi-functional
since it builds pip from source instead of using a wheel with the wrong
entrypoint, we have to update it when this pip version has a release.

Closes #1593.
This commit is contained in:
konsti 2024-03-01 10:05:50 +01:00 committed by GitHub
parent e811070ef1
commit d0ffabd1f2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 37 additions and 34 deletions

View file

@ -88,14 +88,20 @@ pub(crate) fn scripts_from_ini(
// Special case to generate versioned pip launchers.
// https://github.com/pypa/pip/blob/3898741e29b7279e7bffe044ecfbe20f6a438b1e/src/pip/_internal/operations/install/wheel.py#L283
// https://github.com/astral-sh/uv/issues/1593
for script in &mut console_scripts {
// Older pip versions have a wrong `pip3.x` launcher we have to remove, while newer pip versions
// (post https://github.com/pypa/pip/pull/12536) don't, ...
console_scripts.retain(|script| {
let Some((left, right)) = script.name.split_once('.') else {
continue;
return true;
};
if left != "pip3" || right.parse::<u8>().is_err() {
continue;
}
script.name = format!("pip3.{python_minor}");
!(left == "pip3" || right.parse::<u8>().is_ok())
});
// ... either has a `pip3` launcher we can use as template for the `pip3.x` users expect.
if let Some(pip_script) = console_scripts.iter().find(|script| script.name == "pip3") {
console_scripts.push(Script {
name: format!("pip3.{python_minor}"),
..pip_script.clone()
});
}
Ok((console_scripts, gui_scripts))

View file

@ -7,6 +7,7 @@ use std::process::Command;
use anyhow::Result;
use assert_cmd::prelude::*;
use assert_fs::fixture::ChildPath;
use assert_fs::prelude::*;
use indoc::indoc;
use url::Url;
@ -2780,36 +2781,32 @@ fn set_read_permissions() -> Result<()> {
fn pip_entrypoints() -> Result<()> {
let context = TestContext::new("3.12");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.touch()?;
requirements_txt.write_str("pip==24.0")?;
// TODO(konstin): Remove git dep when the next pip version is released.
for pip_requirement in ["pip==24.0", "pip @ git+https://github.com/pypa/pip"] {
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.touch()?;
requirements_txt.write_str(pip_requirement)?;
uv_snapshot!(command(&context)
.arg("requirements.txt")
.arg("--strict"), @r###"
success: true
exit_code: 0
----- stdout -----
command(&context)
.arg("requirements.txt")
.arg("--strict")
.output()
.expect("Failed to install pip");
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ pip==24.0
"###
);
let bin_dir = context.venv.join(if cfg!(unix) {
"bin"
} else if cfg!(windows) {
"Scripts"
} else {
unimplemented!("Only Windows and Unix are supported")
});
// Pip 24.0 contains a pip3.10 launcher.
// https://inspector.pypi.io/project/pip/24.0/packages/8a/6a/19e9fe04fca059ccf770861c7d5721ab4c2aebc539889e97c7977528a53b/pip-24.0-py3-none-any.whl/pip-24.0.dist-info/entry_points.txt
assert!(!bin_dir.join(format!("pip3.10{EXE_SUFFIX}")).exists());
assert!(bin_dir.join(format!("pip3.12{EXE_SUFFIX}")).exists());
let bin_dir = context.venv.join(if cfg!(unix) {
"bin"
} else if cfg!(windows) {
"Scripts"
} else {
unimplemented!("Only Windows and Unix are supported")
});
// Pip 24.0 contains a pip3.10 launcher.
// https://inspector.pypi.io/project/pip/24.0/packages/8a/6a/19e9fe04fca059ccf770861c7d5721ab4c2aebc539889e97c7977528a53b/pip-24.0-py3-none-any.whl/pip-24.0.dist-info/entry_points.txt
ChildPath::new(bin_dir.join(format!("pip3.10{EXE_SUFFIX}")))
.assert(predicates::path::missing());
ChildPath::new(bin_dir.join(format!("pip3.12{EXE_SUFFIX}")))
.assert(predicates::path::exists());
}
Ok(())
}