ModelTranslator: Quit/RunRizomUV 走超时通道防挂死 + _call 分支单测(审查修复)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ud18010
2026-07-17 17:16:00 +08:00
co-authored by Claude Opus 4.8
parent 11d05fbeaa
commit 5de3c17155
2 changed files with 21 additions and 5 deletions
+6 -5
View File
@@ -53,7 +53,8 @@ def find_rizomuv(cli_arg=None, use_registry=True, default=DEFAULT_RIZOM):
def _import_link(exe): def _import_link(exe):
"""从 RizomUV 安装目录动态引入官方 RizomUVLink 模块(随安装自带,MIT)。""" """从 RizomUV 安装目录动态引入官方 RizomUVLink 模块(随安装自带,MIT)。
同进程只支持单一安装路径(import 缓存,首次 import 后不会再切换目录)。"""
link_dir = os.path.join(os.path.dirname(exe), "RizomUVLink") link_dir = os.path.join(os.path.dirname(exe), "RizomUVLink")
if not os.path.isdir(link_dir): if not os.path.isdir(link_dir):
raise RizomError("RizomUVLink 目录不存在:%s" % link_dir) raise RizomError("RizomUVLink 目录不存在:%s" % link_dir)
@@ -95,8 +96,8 @@ def rizom_unwrap(fbx_path, exe, map_res=MAP_RES, padding_px=PADDING_PX):
mod = _import_link(exe) mod = _import_link(exe)
link = mod.CRizomUVLink() link = mod.CRizomUVLink()
try: try:
link.RunRizomUV(exePath=exe) _call("RunRizomUV", lambda _p: link.RunRizomUV(exePath=exe), None, timeout=60)
except Exception as e: except RizomError as e:
raise RizomError("RizomUV 启动失败(license/环境):%s" % e) raise RizomError("RizomUV 启动失败(license/环境):%s" % e)
fbx_abs = os.path.abspath(fbx_path) fbx_abs = os.path.abspath(fbx_path)
pad_uv = float(padding_px) / map_res pad_uv = float(padding_px) / map_res
@@ -137,6 +138,6 @@ def rizom_unwrap(fbx_path, exe, map_res=MAP_RES, padding_px=PADDING_PX):
_call("Save", link.Save, {"File.Path": fbx_abs}) _call("Save", link.Save, {"File.Path": fbx_abs})
finally: finally:
try: try:
link.Quit({}) _call("Quit", link.Quit, {}, timeout=10)
except Exception: except Exception:
pass print("[警告] RizomUV Quit 未确认,可能残留 rizomuv 进程占用 license")
@@ -1,5 +1,6 @@
import os import os
import sys import sys
import time
import unittest import unittest
from unittest import mock from unittest import mock
@@ -35,5 +36,19 @@ class TestFindRizomuv(unittest.TestCase):
self.assertTrue(os.path.isfile(p), "注册表返回值应是真实 exe%s" % p) self.assertTrue(os.path.isfile(p), "注册表返回值应是真实 exe%s" % p)
class TestCall(unittest.TestCase):
def test_timeout_raises(self):
with self.assertRaises(ru.RizomError) as cm:
ru._call("Slow", lambda p: time.sleep(1.0), None, timeout=0.05)
self.assertIn("超时", str(cm.exception))
def test_error_dict_raises(self):
with self.assertRaises(ru.RizomError):
ru._call("Bad", lambda p: {"Error": {"Msg": "x", "Code": 1}}, {})
def test_normal_dict_passes_through(self):
self.assertEqual(ru._call("Ok", lambda p: {"Data": 1}, {}), {"Data": 1})
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()