fix: close bare open() in host.py and ResourceWarning in test_host_thread_cli

- host.py: 7 one-shot reads switched to with open (run_health_check
  pidfile, daemon-status pid/log, daemon-stop pid, daemon old pid,
  interrupt poll state, parallel jobs); read content, encoding args
  and error semantics unchanged.
- tests/test_host_thread_cli.py: test_old_archive_unchanged state
  read switched to with open; added a warnings-capture assertion
  scoped to the state read so a regression fails the test.
- Intentionally untouched: daemonize log handle (daemon-lifetime
  dup2 target) and the two _load_config_file / init sites owned
  by PR #266.
This commit is contained in:
host committed 2026-11-03 02:49:26 +00:00
1 parent 72d343b2c7
commit 436a92ba1d
2 files changed
+29 -9

No files matched your search

+14 -8
View File
@@ -1120,7 +1120,8 @@ def run_health_check(state_path, cfg, codex_bin, codex_home, approval,
checks["daemon_pidfile"] = pidfile
if os.path.exists(pidfile):
try:
pid = int(open(pidfile).read().strip())
with open(pidfile) as f:
pid = int(f.read().strip())
os.kill(pid, 0)
checks["daemon_alive"] = True
checks["daemon_pid"] = pid
@@ -2707,7 +2708,8 @@ def main():
pid = None
if os.path.exists(pidfile):
try:
pid = int(open(pidfile).read().strip())
with open(pidfile) as f:
pid = int(f.read().strip())
os.kill(pid, 0)
alive = True
except Exception:
@@ -2715,7 +2717,8 @@ def main():
tail = ""
if os.path.exists(logfile):
try:
tail = "\n".join(open(logfile).read().splitlines()[-5:])
with open(logfile) as f:
tail = "\n".join(f.read().splitlines()[-5:])
except Exception:
pass
print(json.dumps({"alive": alive, "pid": pid, "pidfile": pidfile,
@@ -2728,7 +2731,8 @@ def main():
print("daemon 未运行(无 pidfile)")
return
try:
pid = int(open(pidfile).read().strip())
with open(pidfile) as f:
pid = int(f.read().strip())
except Exception:
print("pidfile 损坏,直接删除")
os.remove(pidfile)
@@ -2758,7 +2762,8 @@ def main():
if not args.foreground:
if os.path.exists(pidfile):
try:
old_pid = int(open(pidfile).read().strip())
with open(pidfile) as f:
old_pid = int(f.read().strip())
os.kill(old_pid, 0)
print(f"daemon 已在运行:pid {old_pid},先 daemon-stop 再起")
return
@@ -3272,8 +3277,8 @@ def main():
for _ in range(10):
time.sleep(1)
try:
cur = json.load(open(args.state,
encoding="utf-8"))
with open(args.state, encoding="utf-8") as f:
cur = json.load(f)
if (cur.get("tasks", {}).get(args.task, {})
.get("status") == "interrupted"):
print(f"interrupt {args.task}: 属主已响应,"
@@ -3424,7 +3429,8 @@ def main():
last_turn_status=t.get("goal_last_turn_status"),
last_turn_text=last_result.get("text", "") or "")
elif args.cmd == "parallel":
jobs = json.load(open(args.jobs))
with open(args.jobs) as f:
jobs = json.load(f)
# 依赖 + 优先级:先拓扑排序,缺依赖/成环直接报错不跑;
# 按波次派发 + 跑:依赖都 completed 的任务才进本波,
# 依赖 failed/skipped 的任务标 skipped 不跑,避免在坏
+15 -1
View File
@@ -1,9 +1,11 @@
import gc
import io
import json
import os
import sys
import tempfile
import unittest
import warnings
from contextlib import redirect_stdout
from unittest import mock
import host
@@ -246,7 +248,19 @@ class ThreadCliTest(unittest.TestCase):
code = e.code if isinstance(e.code, int) else 1
self.assertEqual(code, 0)
self.assertIn("archived t1", out.getvalue())
saved = json.loads(Path(state_path).read_text(encoding="utf-8"))
# 第 4 项回归:此处裸 open() 曾在 GC 时报 ResourceWarning;
# 只捕获本段读 state 的警告断言(_load_config_file 的
# 警告属 #266 轨,不在此断言范围内)。
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always", ResourceWarning)
with open(state_path, encoding="utf-8") as f:
saved = json.load(f)
gc.collect()
self.assertEqual(
[w for w in caught
if issubclass(w.category, ResourceWarning)
and "host-state.json" in str(w.message)],
[])
self.assertEqual(saved["tasks"]["t1"]["status"], "archived")
calls = self._calls_before_close(fake)
self.assertEqual(calls, [("archive", "th-1")])