Coverage for adrs/installer.py: 0%
57 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-29 04:01 +0800
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-29 04:01 +0800
1import os
2import sys
3import platform
4import importlib
5import ensurepip
6import subprocess
7from pathlib import Path
10def ensure_one(pkg: str, version: str):
11 if _is_installed(pkg):
12 return
14 wheel_path = resolve_wheel(pkg, version)
15 print(f"Installing {pkg}=={version}")
16 install_wheel(wheel_path)
17 print(f"Installed {pkg}=={version}")
20def _is_installed(pkg: str) -> bool:
21 try:
22 importlib.import_module(pkg)
23 return True
24 except ImportError:
25 return False
28def resolve_wheel(pkg: str, version: str) -> Path:
29 """
30 Attempts to find a matching wheel by iterating over all
31 compatible sys_tags. This gives reliable fallback behavior.
32 """
33 for wheel_filename in derive_possible_wheels(pkg, version):
34 wheel_path = download_wheel(pkg, version, wheel_filename)
35 if wheel_path is not None:
36 return wheel_path
38 raise RuntimeError(
39 f"No compatible wheel found for {pkg}={version}. "
40 "Check that your platform and python version is supported."
41 )
44def derive_possible_wheels(pkg: str, version: str) -> list[str]:
45 """
46 Derives a packaging tag for the current system.
47 """
48 system = platform.system().lower()
49 arch = platform.machine().lower()
50 pyver = f"cp{sys.version_info.major}{sys.version_info.minor}"
52 wheels = []
53 match system:
54 case "linux":
55 wheels = [
56 f"{pkg}-{version}-{pyver}-{pyver}-manylinux_2_17_{arch}.manylinux2014_{arch}.whl"
57 ]
58 case "darwin":
59 wheels = [
60 f"{pkg}-{version}-{pyver}-{pyver}-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"
61 ]
62 case "windows":
63 wheels = [f"{pkg}-{version}-{pyver}-{pyver}-win_{arch}.whl"]
65 return wheels
68def download_wheel(pkg: str, version: str, filename: str) -> Path | None:
69 """ """
70 WHEEL_DIR = Path(__file__).parent / "wheels"
71 os.makedirs(WHEEL_DIR, exist_ok=True)
73 wheel_path = WHEEL_DIR / filename
74 if wheel_path.exists():
75 return wheel_path
77 return None
80def install_wheel(wheel_path: Path):
81 """
82 Install a wheel from a local file, ensuring pip is available.
83 """
84 try:
85 # Try pip first
86 subprocess.run(
87 [
88 sys.executable,
89 "-m",
90 "pip",
91 "install",
92 "--no-deps",
93 str(wheel_path),
94 ],
95 check=True,
96 capture_output=True,
97 text=True,
98 )
99 except subprocess.CalledProcessError as e:
100 if "No module named pip" in e.stderr:
101 print("[adrs] pip not found, bootstrapping pip...")
102 ensurepip.bootstrap()
103 subprocess.check_call(
104 [
105 sys.executable,
106 "-m",
107 "pip",
108 "install",
109 "--no-deps",
110 str(wheel_path),
111 ]
112 )
113 else:
114 raise RuntimeError(f"Failed to install {wheel_path}: {e}") from e
115 except Exception as e:
116 raise RuntimeError(f"Failed to install {wheel_path}: {e}") from e