tripocli v2.0.0:Tripo AI 3D 生成与加工 CLI(面向 Agent 与开发者,纯 Python 标准库、零第三方依赖)

覆盖文生 3D、图生 3D、多视图、批量生成,以及重拓扑、绑定、动画、智能分割、
纹理、PBR、智能 UV、部件补全、格式导出与下载。

代码组织:一个功能一个模块(tripo/features/),入口薄壳 tripocli.py。
This commit is contained in:
Mrpzx committed 2026-10-13 19:22:54 +08:00
commit 977f97995a
60 files changed
+5622

No files matched your search

+128
View File
@@ -0,0 +1,128 @@
"""Self-update: refresh the installed CLI from the project source tree.
The project is distributed as a source directory (no PyPI release yet), so
"updating" means: find the source tree, re-install it with the *same*
interpreter that is running us, and rehash pyenv shims if pyenv is in use.
The source directory is remembered in ``~/.tripo/config.json`` (``install_source``)
the first time it is discovered, so later runs only need ``tripocli update``.
"""
import json
import os
import shutil
import subprocess
import sys
from pathlib import Path
from . import __version__
INSTALL_SOURCE_KEY = "install_source"
def _running_package_dir():
"""Directory of the ``tripo`` package that is currently imported."""
return Path(__file__).resolve().parent
def _is_site_packages(path):
parts = {p.lower() for p in Path(path).parts}
return bool(parts & {"site-packages", "dist-packages"})
def detect_source(explicit=None, config=None):
"""Locate the source tree to install from.
Order: ``--from`` > remembered ``install_source`` > the tree we were imported
from (only when that is not site-packages).
"""
if explicit:
candidate = Path(explicit).expanduser().resolve()
if not (candidate / "pyproject.toml").exists():
raise ValueError(f"{candidate} 看起来不是项目目录(缺少 pyproject.toml)")
return candidate
if config:
remembered = config.data.get(INSTALL_SOURCE_KEY)
if remembered and (Path(remembered) / "pyproject.toml").exists():
return Path(remembered)
package_dir = _running_package_dir()
if not _is_site_packages(package_dir):
root = package_dir.parent
if (root / "pyproject.toml").exists():
return root
return None
def installed_version():
"""Version of the copy in site-packages (what other directories will run)."""
try:
out = subprocess.run(
[sys.executable, "-m", "pip", "show", "tripocli"],
capture_output=True, text=True, timeout=60,
)
except (OSError, subprocess.SubprocessError):
return None
for line in out.stdout.splitlines():
if line.lower().startswith("version:"):
return line.split(":", 1)[1].strip()
return None
def _has_pyenv():
return bool(shutil.which("pyenv") or os.environ.get("PYENV_ROOT"))
def update(source, rehash=True, dry_run=False):
"""Re-install ``source`` with the running interpreter. Returns a report dict."""
source = Path(source)
steps = []
command = [
sys.executable, "-m", "pip", "install",
"--no-build-isolation", "--no-deps", "--upgrade", "--force-reinstall", str(source),
]
if dry_run:
planned = [" ".join(command)]
if rehash and _has_pyenv():
planned.append("pyenv rehash")
return {"source": str(source), "command": command, "steps": planned,
"rehash": False, "dry_run": True, "version": __version__}
proc = subprocess.run(command, capture_output=True, text=True)
steps.append(" ".join(command))
tail = "\n".join((proc.stdout or "").strip().splitlines()[-6:])
if proc.returncode != 0:
raise RuntimeError(
f"pip 安装失败(退出码 {proc.returncode}):\n{(proc.stderr or proc.stdout or '')[-800:]}"
)
steps.append(tail)
rehashed = False
if rehash and _has_pyenv():
subprocess.run(["pyenv", "rehash"], capture_output=True, text=True)
steps.append("pyenv rehash")
rehashed = True
return {
"source": str(source),
"command": command,
"steps": steps,
"rehash": rehashed,
"version": __version__,
"installed_version": installed_version(),
}
def report_lines(report):
prefix = "将执行" if report.get("dry_run") else "已执行"
lines = [
f"源码目录 : {report['source']}",
f"版本 : {report.get('installed_version') or report['version']}",
f"{prefix} : {'; '.join(report['steps'])}",
]
if report.get("rehash"):
lines.append("已执行 : pyenv rehash")
return lines