fix: Ubuntu 24.04 等 PEP668 系统 Python 安装时自动加 --break-system-packages(安装/升级/卸载全链路)
This commit is contained in:
@@ -57,10 +57,16 @@ def _remove_path(path: Path, removed: list[Path]) -> None:
|
|||||||
|
|
||||||
def _pip_uninstall() -> list[str]:
|
def _pip_uninstall() -> list[str]:
|
||||||
"""Uninstall the pip packages (removes their pip-owned entry points)."""
|
"""Uninstall the pip packages (removes their pip-owned entry points)."""
|
||||||
|
import sysconfig
|
||||||
|
|
||||||
if os.environ.get("VIRTUAL_ENV") and shutil.which("uv"):
|
if os.environ.get("VIRTUAL_ENV") and shutil.which("uv"):
|
||||||
base = ["uv", "pip", "uninstall"]
|
base = ["uv", "pip", "uninstall"]
|
||||||
else:
|
else:
|
||||||
base = [sys.executable, "-m", "pip", "uninstall", "-y"]
|
base = [sys.executable, "-m", "pip", "uninstall"]
|
||||||
|
stdlib = Path(sysconfig.get_path("stdlib"))
|
||||||
|
if (stdlib / "EXTERNALLY-MANAGED").exists():
|
||||||
|
base.append("--break-system-packages")
|
||||||
|
base.append("-y")
|
||||||
warnings: list[str] = []
|
warnings: list[str] = []
|
||||||
for pkg in PY_PACKAGES:
|
for pkg in PY_PACKAGES:
|
||||||
result = subprocess.run([*base, pkg], capture_output=True, text=True)
|
result = subprocess.run([*base, pkg], capture_output=True, text=True)
|
||||||
|
|||||||
@@ -147,11 +147,18 @@ def _extract(tarball: Path, dest: Path) -> None:
|
|||||||
|
|
||||||
def _pip_install(pkg_dir: Path) -> subprocess.CompletedProcess:
|
def _pip_install(pkg_dir: Path) -> subprocess.CompletedProcess:
|
||||||
import os
|
import os
|
||||||
|
import sysconfig
|
||||||
|
|
||||||
if os.environ.get("VIRTUAL_ENV") and shutil.which("uv"):
|
if os.environ.get("VIRTUAL_ENV") and shutil.which("uv"):
|
||||||
cmd = ["uv", "pip", "install", "-e", str(pkg_dir), "--quiet"]
|
cmd = ["uv", "pip", "install", "-e", str(pkg_dir), "--quiet"]
|
||||||
else:
|
else:
|
||||||
cmd = [sys.executable, "-m", "pip", "install", "-e", str(pkg_dir), "--quiet"]
|
cmd = [sys.executable, "-m", "pip", "install"]
|
||||||
|
# Ubuntu 24.04+ marks the system Python externally-managed (PEP 668);
|
||||||
|
# without the flag pip refuses to install there at all.
|
||||||
|
stdlib = Path(sysconfig.get_path("stdlib"))
|
||||||
|
if (stdlib / "EXTERNALLY-MANAGED").exists():
|
||||||
|
cmd.append("--break-system-packages")
|
||||||
|
cmd += ["-e", str(pkg_dir), "--quiet"]
|
||||||
return subprocess.run(cmd, capture_output=True, text=True)
|
return subprocess.run(cmd, capture_output=True, text=True)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -230,3 +230,41 @@ class TestFetch:
|
|||||||
dest = tmp_path / "out.tar.gz"
|
dest = tmp_path / "out.tar.gz"
|
||||||
up_mod._download("http://x/f", "u", "p", dest)
|
up_mod._download("http://x/f", "u", "p", dest)
|
||||||
assert dest.read_bytes() == payload
|
assert dest.read_bytes() == payload
|
||||||
|
|
||||||
|
|
||||||
|
class TestPipInstallFlags:
|
||||||
|
def test_uses_break_system_packages_on_externally_managed(
|
||||||
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||||
|
) -> None:
|
||||||
|
import sysconfig
|
||||||
|
|
||||||
|
em = tmp_path / "EXTERNALLY-MANAGED"
|
||||||
|
em.write_text("[externally-managed]\n")
|
||||||
|
monkeypatch.setattr(
|
||||||
|
sysconfig, "get_path", lambda name: str(tmp_path) if name == "stdlib" else ""
|
||||||
|
)
|
||||||
|
seen: list[list[str]] = []
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"subprocess.run",
|
||||||
|
lambda cmd, **kw: seen.append(cmd)
|
||||||
|
or type("R", (), {"returncode": 0, "stderr": ""})(),
|
||||||
|
)
|
||||||
|
up_mod._pip_install(tmp_path / "pkg")
|
||||||
|
assert "--break-system-packages" in seen[0]
|
||||||
|
|
||||||
|
def test_skips_flag_without_externally_managed(
|
||||||
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||||
|
) -> None:
|
||||||
|
import sysconfig
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
sysconfig, "get_path", lambda name: str(tmp_path) if name == "stdlib" else ""
|
||||||
|
)
|
||||||
|
seen: list[list[str]] = []
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"subprocess.run",
|
||||||
|
lambda cmd, **kw: seen.append(cmd)
|
||||||
|
or type("R", (), {"returncode": 0, "stderr": ""})(),
|
||||||
|
)
|
||||||
|
up_mod._pip_install(tmp_path / "pkg")
|
||||||
|
assert "--break-system-packages" not in seen[0]
|
||||||
|
|||||||
Reference in New Issue
Block a user