# -*- coding: utf-8 -*- # Copyright (c) 2025 relakkes@gmail.com # # This file is part of MediaCrawler project. # Repository: https://github.com/NanmiCoder/MediaCrawler/blob/main/api/services/interpreter.py # GitHub: https://github.com/NanmiCoder # Licensed under NON-COMMERCIAL LEARNING LICENSE 1.1 # # 声明:本代码仅供学习和研究目的使用。使用者应遵守以下原则: # 1. 不得用于任何商业用途。 # 2. 使用时应遵守目标平台的使用条款和robots.txt规则。 # 3. 不得进行大规模爬取或对平台造成运营干扰。 # 4. 应合理控制请求频率,避免给目标平台带来不必要的负担。 # 5. 不得用于任何非法或不当的用途。 # # 详细许可条款请参阅项目根目录下的LICENSE文件。 # 使用本代码即表示您同意遵守上述原则和LICENSE中的所有条款。 """Interpreter resolution for spawning crawler subprocesses. Historically both the crawler manager and the environment check hardcoded ``uv run``. ``uv`` is not guaranteed to be installed, so resolve the command prefix in one place: prefer ``uv`` (matching upstream docs), fall back to a project-local virtualenv, and finally to the interpreter running the server. """ import shutil import sys from pathlib import Path # Project root: api/services/interpreter.py -> services -> api -> repo root PROJECT_ROOT = Path(__file__).parent.parent.parent def venv_python_path(project_root: Path | None = None) -> Path: """Return the path to the project venv's Python executable.""" root = project_root if project_root is not None else PROJECT_ROOT if sys.platform == "win32": return root / ".venv" / "Scripts" / "python.exe" return root / ".venv" / "bin" / "python" def resolve_python_cmd(project_root: Path | None = None) -> list[str]: """Resolve the command prefix used to run ``main.py``. Order of preference: 1. ``uv`` if it is on PATH -- matches the upstream documented workflow. 2. The project-local ``.venv`` if it exists. 3. The interpreter currently running the API server. Returns a list because the caller appends ``main.py`` and its flags. """ if shutil.which("uv"): return ["uv", "run", "python"] venv_python = venv_python_path(project_root) if venv_python.exists(): return [str(venv_python)] return [sys.executable] def describe_interpreter(project_root: Path | None = None) -> str: """Human-readable description of what resolve_python_cmd() picks.""" cmd = resolve_python_cmd(project_root) if cmd[0] == "uv": return "uv run python" if cmd[0] == sys.executable: return f"current interpreter ({sys.executable})" return f"project virtualenv ({cmd[0]})"