diff --git a/astrbot/core/utils/pip_installer.py b/astrbot/core/utils/pip_installer.py index afde805ff..a9f441099 100644 --- a/astrbot/core/utils/pip_installer.py +++ b/astrbot/core/utils/pip_installer.py @@ -5,7 +5,9 @@ import locale import logging import os +import shutil import sys +from pathlib import Path from astrbot.core.utils.astrbot_path import get_astrbot_site_packages_path @@ -34,6 +36,28 @@ def _is_frozen_runtime() -> bool: return bool(getattr(sys, "frozen", False)) +def _get_pip_subprocess_executable() -> str | None: + candidates = [ + getattr(sys, "_base_executable", None), + sys.executable, + shutil.which("python3"), + shutil.which("python"), + ] + + for candidate in candidates: + if not candidate: + continue + + candidate_path = Path(candidate) + with contextlib.suppress(OSError): + candidate_path = candidate_path.resolve() + + if candidate_path.is_file() and os.access(candidate_path, os.X_OK): + return str(candidate_path) + + return None + + def _get_pip_main(): try: from pip._internal.cli.main import main as pip_main @@ -92,13 +116,26 @@ async def install( logger.info(f"Pip 包管理器: pip {' '.join(args)}") result_code = None - if _is_frozen_runtime(): - result_code = await self._run_pip_in_process(args) - else: + + subprocess_executable = _get_pip_subprocess_executable() + if subprocess_executable: try: - result_code = await self._run_pip_subprocess(args) - except FileNotFoundError: - result_code = await self._run_pip_in_process(args) + result_code = await self._run_pip_subprocess( + subprocess_executable, args + ) + except OSError as exc: + logger.warning( + "Failed to launch pip subprocess (%r). Falling back to in-process pip: %s", + subprocess_executable, + exc, + ) + else: + logger.debug( + "No suitable Python executable found for pip subprocess; using in-process pip" + ) + + if result_code is None: + result_code = await self._run_pip_in_process(args) if result_code != 0: raise Exception(f"安装失败,错误码:{result_code}") @@ -107,9 +144,9 @@ async def install( sys.path.insert(0, target_site_packages) importlib.invalidate_caches() - async def _run_pip_subprocess(self, args: list[str]) -> int: + async def _run_pip_subprocess(self, executable: str, args: list[str]) -> int: process = await asyncio.create_subprocess_exec( - sys.executable, + executable, "-m", "pip", *args,