fix: hide cmhub curl download window
This commit is contained in:
@@ -1452,6 +1452,21 @@ def _find_system_curl():
|
||||
return ""
|
||||
|
||||
|
||||
def _subprocess_hidden_window_kwargs():
|
||||
if os.name != "nt":
|
||||
return {}
|
||||
creationflags = getattr(subprocess, "CREATE_NO_WINDOW", 0)
|
||||
if creationflags:
|
||||
return {"creationflags": creationflags}
|
||||
startupinfo_cls = getattr(subprocess, "STARTUPINFO", None)
|
||||
if startupinfo_cls is None:
|
||||
return {}
|
||||
startupinfo = startupinfo_cls()
|
||||
startupinfo.dwFlags |= getattr(subprocess, "STARTF_USESHOWWINDOW", 1)
|
||||
startupinfo.wShowWindow = getattr(subprocess, "SW_HIDE", 0)
|
||||
return {"startupinfo": startupinfo}
|
||||
|
||||
|
||||
def _download_cmhub_image_with_curl(
|
||||
url,
|
||||
connect_timeout,
|
||||
@@ -1501,6 +1516,7 @@ def _download_cmhub_image_with_curl(
|
||||
timeout=max(2, int(connect_timeout) + int(read_timeout) + 10),
|
||||
check=False,
|
||||
shell=False,
|
||||
**_subprocess_hidden_window_kwargs(),
|
||||
)
|
||||
except (OSError, subprocess.TimeoutExpired) as exc:
|
||||
raise AIError("下载 cmhub 图片失败: curl 执行失败") from exc
|
||||
|
||||
+5
-1
@@ -3,7 +3,7 @@ id: T-561
|
||||
title: cmhub curl 下载隐藏 Windows 黑窗
|
||||
phase: 7
|
||||
deps: [T-548, T-524]
|
||||
status: TODO
|
||||
status: DONE
|
||||
created: 2026-07-08
|
||||
---
|
||||
|
||||
@@ -46,3 +46,7 @@ T-548 后,②AI生成在 Windows 下默认优先调用系统 `curl.exe` 下载
|
||||
|
||||
## 执行记录
|
||||
|
||||
- 2026-07-08:`app/ai.py` 新增 `_subprocess_hidden_window_kwargs()`,Windows 下优先使用 `subprocess.CREATE_NO_WINDOW` 隐藏 curl 子进程控制台窗口;缺少该常量时兜底 `STARTUPINFO + STARTF_USESHOWWINDOW + SW_HIDE`;非 Windows 返回空参数。
|
||||
- 2026-07-08:`_download_cmhub_image_with_curl()` 调用 `subprocess.run()` 时传入隐藏窗口 kwargs,保留 `shell=False`、`-K` 临时配置文件、`--noproxy`、超时、大小上限、stderr/stdout 捕获和 requests fallback 语义。
|
||||
- 2026-07-08:更新 `tests/test_ai.py`,覆盖 Windows curl 调用携带隐藏窗口参数、URL 不在 argv、`shell=False` 保持,以及非 Windows 不加隐藏窗口参数。
|
||||
- 验证通过:`py -3.10 -m unittest tests.test_ai.AITests.test_cmhub_image_download_uses_curl_without_url_in_argv tests.test_ai.AITests.test_cmhub_curl_hidden_window_kwargs_are_windows_only tests.test_ai.AITests.test_cmhub_image_download_falls_back_to_requests_when_curl_fails tests.test_ai.AITests.test_cmhub_image_download_auto_without_curl_uses_requests`、`python -m ruff check app tests main.py`。
|
||||
|
||||
+15
-1
@@ -725,12 +725,15 @@ class AITests(TempDirMixin, unittest.TestCase):
|
||||
self.assertIn("--noproxy", args)
|
||||
self.assertEqual("*", args[args.index("--noproxy") + 1])
|
||||
self.assertFalse(kwargs["shell"])
|
||||
self.assertEqual(0x08000000, kwargs["creationflags"])
|
||||
output_path = args[args.index("--output") + 1]
|
||||
with open(output_path, "wb") as fh:
|
||||
fh.write(generated_png)
|
||||
return SimpleNamespace(returncode=0, stdout=b"", stderr=b"")
|
||||
|
||||
with mock.patch("app.ai._find_system_curl", return_value=r"C:\Windows\System32\curl.exe"), \
|
||||
with mock.patch("app.ai.os.name", "nt"), \
|
||||
mock.patch("app.ai.subprocess.CREATE_NO_WINDOW", 0x08000000, create=True), \
|
||||
mock.patch("app.ai._find_system_curl", return_value=r"C:\Windows\System32\curl.exe"), \
|
||||
mock.patch("app.ai.subprocess.run", side_effect=fake_run), \
|
||||
mock.patch("app.ai.socket.getaddrinfo", return_value=public_dns):
|
||||
image_bytes = ai._download_cmhub_image(
|
||||
@@ -744,6 +747,17 @@ class AITests(TempDirMixin, unittest.TestCase):
|
||||
self.assertEqual(generated_png, image_bytes)
|
||||
self.assertEqual(1, len(calls))
|
||||
|
||||
def test_cmhub_curl_hidden_window_kwargs_are_windows_only(self):
|
||||
with mock.patch("app.ai.os.name", "nt"), \
|
||||
mock.patch("app.ai.subprocess.CREATE_NO_WINDOW", 0x08000000, create=True):
|
||||
self.assertEqual(
|
||||
{"creationflags": 0x08000000},
|
||||
ai._subprocess_hidden_window_kwargs(),
|
||||
)
|
||||
|
||||
with mock.patch("app.ai.os.name", "posix"):
|
||||
self.assertEqual({}, ai._subprocess_hidden_window_kwargs())
|
||||
|
||||
def test_cmhub_image_download_skips_curl_for_private_url(self):
|
||||
with mock.patch("app.ai._find_system_curl", return_value=r"C:\Windows\System32\curl.exe"), \
|
||||
mock.patch("app.ai.subprocess.run") as run:
|
||||
|
||||
Reference in New Issue
Block a user