new hyrdusupdate

This commit is contained in:
2026-04-01 14:14:29 -07:00
parent 849dcbda85
commit 675ae8a62c

View File

@@ -692,12 +692,146 @@ IMPORT_NAME_OVERRIDES = {
} }
def normalize_python_command(python_cmd: Optional[Sequence[str] | str]) -> list[str]:
if python_cmd is None:
return [sys.executable]
if isinstance(python_cmd, (str, Path)):
return [str(python_cmd)]
return [str(part) for part in python_cmd]
def get_python_version_info(python_cmd: Optional[Sequence[str] | str] = None) -> Optional[tuple[int, int, int]]:
cmd = normalize_python_command(python_cmd)
try:
result = subprocess.run(
cmd + [
"-c",
"import sys; print('.'.join(str(part) for part in sys.version_info[:3]))",
],
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
text=True,
check=True,
)
version_text = (result.stdout or "").strip()
major, minor, micro = version_text.split(".", 2)
return (int(major), int(minor), int(micro))
except Exception:
return None
def is_hydrus_repo(repo_root: Path) -> bool:
return (repo_root / "setup_venv.py").exists() and (repo_root / "hydrus_client.py").exists()
def select_hydrus_python_command() -> tuple[list[str], tuple[int, int, int]]:
candidates: list[list[str]] = []
if os.name == "nt" and shutil.which("py"):
for version in ("3.12", "3.11", "3.10", "3.13", "3.14"):
candidates.append(["py", f"-{version}"])
candidates.append([sys.executable])
for name in ("python3.12", "python3.11", "python3.10", "python3", "python"):
resolved = shutil.which(name)
if resolved:
candidates.append([resolved])
seen: set[tuple[str, ...]] = set()
best_fallback: Optional[tuple[list[str], tuple[int, int, int]]] = None
for candidate in candidates:
normalized = tuple(candidate)
if normalized in seen:
continue
seen.add(normalized)
version = get_python_version_info(candidate)
if version is None or version < (3, 10):
continue
if version < (3, 13):
return candidate, version
if best_fallback is None or version < best_fallback[1]:
best_fallback = (candidate, version)
if best_fallback is not None:
return best_fallback
version = get_python_version_info([sys.executable])
if version is None:
raise RuntimeError("Could not determine a usable Python interpreter for Hydrus")
return [sys.executable], version
def build_hydrus_install_targets(
req_path: Path,
repo_root: Path,
python_version: tuple[int, int, int],
) -> list[str]:
if not is_hydrus_repo(repo_root) or python_version < (3, 13):
return ["-r", str(req_path)]
overrides = {
"pyside6": "PySide6==6.10.1",
"qtpy": "QtPy==2.4.3",
"opencv-python-headless": "opencv-python-headless==4.13.0.90",
"numpy": "numpy==2.4.1",
}
targets: list[str] = []
seen_packages: set[str] = set()
for raw_line in req_path.read_text(encoding="utf-8").splitlines():
line = raw_line.strip()
if not line or line.startswith("#"):
continue
package_name = re.split(r"[<>=!~\[]", line, maxsplit=1)[0].strip().lower()
if package_name in overrides:
line = overrides[package_name]
targets.append(line)
seen_packages.add(package_name)
if os.name == "nt" and "pywin32" not in seen_packages:
targets.append("pywin32")
logging.info(
"Using Hydrus compatibility dependency set for Python %s.%s.%s",
python_version[0],
python_version[1],
python_version[2],
)
return targets
def ensure_repo_venv( def ensure_repo_venv(
repo_root: Path, repo_root: Path,
venv_name: str = ".venv", venv_name: str = ".venv",
recreate: bool = False, recreate: bool = False,
purpose: Optional[str] = None, purpose: Optional[str] = None,
) -> Path: ) -> Path:
python_cmd: list[str]
python_version: Optional[tuple[int, int, int]]
if is_hydrus_repo(repo_root):
python_cmd, python_version = select_hydrus_python_command()
if python_version is not None:
logging.info(
"Using Python %s.%s.%s for Hydrus venv creation via %s",
python_version[0],
python_version[1],
python_version[2],
" ".join(python_cmd),
)
if python_version >= (3, 13):
logging.info(
"Hydrus is running on a newer Python; installer will apply compatibility package overrides."
)
else:
python_cmd = [sys.executable]
venv_dir = repo_root / str(venv_name) venv_dir = repo_root / str(venv_name)
if venv_dir.exists(): if venv_dir.exists():
if recreate: if recreate:
@@ -711,7 +845,7 @@ def ensure_repo_venv(
logging.info("Creating venv at %s for %s", venv_dir, purpose) logging.info("Creating venv at %s for %s", venv_dir, purpose)
else: else:
logging.info("Creating venv at %s", venv_dir) logging.info("Creating venv at %s", venv_dir)
subprocess.run([sys.executable, "-m", "venv", str(venv_dir)], check=True) subprocess.run(python_cmd + ["-m", "venv", str(venv_dir)], check=True)
venv_py = get_python_in_venv(venv_dir) venv_py = get_python_in_venv(venv_dir)
if not venv_py: if not venv_py:
@@ -727,6 +861,10 @@ def install_requirements_into_venv(
req_path: Path, req_path: Path,
reinstall: bool = False, reinstall: bool = False,
) -> None: ) -> None:
python_version = get_python_version_info([str(venv_py)])
if python_version is None:
raise RuntimeError(f"Could not determine python version for {venv_py}")
logging.info( logging.info(
"Installing dependencies from %s into venv (reinstall=%s)", "Installing dependencies from %s into venv (reinstall=%s)",
req_path, req_path,
@@ -751,10 +889,11 @@ def install_requirements_into_venv(
"pip", "pip",
"install", "install",
"--disable-pip-version-check", "--disable-pip-version-check",
"--prefer-binary",
] ]
if reinstall: if reinstall:
cmd.extend(["--upgrade", "--force-reinstall"]) cmd.extend(["--upgrade", "--force-reinstall"])
cmd.extend(["-r", str(req_path)]) cmd.extend(build_hydrus_install_targets(req_path, repo_root, python_version))
subprocess.run(cmd, cwd=str(repo_root), check=True) subprocess.run(cmd, cwd=str(repo_root), check=True)
logging.info("Dependencies installed successfully") logging.info("Dependencies installed successfully")