Compare commits

..

2 Commits

Author SHA1 Message Date
revernomad17
4478ec3cab docs: document run_tool subprocess streaming pattern in CLAUDE.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 16:11:24 +07:00
revernomad17
b7dbf54512 Fix tool log streaming — switch from subprocess.run to Popen
subprocess.run with capture_output=True blocked until process exit,
dumping all output at once. Now uses Popen with line-by-line reading,
-u flag, and PYTHONUNBUFFERED=1 so logs stream in real time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 16:10:36 +07:00
2 changed files with 17 additions and 9 deletions

View File

@@ -108,6 +108,8 @@ Pass 2 builds `ok_disk_names` — the set of disk names that already match the s
**`selection.json`** — GUI selection state file, tracked in git. Persists which mods/groups are selected between GUI sessions. Written by the GUI; safe to delete (GUI recreates it on next save). **`selection.json`** — GUI selection state file, tracked in git. Persists which mods/groups are selected between GUI sessions. Written by the GUI; safe to delete (GUI recreates it on next save).
**`run_tool` subprocess streaming:** Tool scripts are launched via `subprocess.Popen` (not `subprocess.run`) with `stdout=PIPE, stderr=STDOUT`, read line-by-line via `iter(proc.stdout.readline, "")`, and posted to the log queue immediately. Python's own output buffering is disabled with the `-u` flag and `PYTHONUNBUFFERED=1` in the environment — without these, output would batch inside the pipe and only appear when the script exits.
## Python Version Compatibility ## Python Version Compatibility
Minimum is Python **3.9**. All files that use `X | Y` union type annotations **must** have `from __future__ import annotations` as the first import. Without it, the `|` syntax raises `TypeError` at runtime on Python < 3.10. Every module in `arma_modlist_tools/` already has it; any new CLI script you add must include it too. Minimum is Python **3.9**. All files that use `X | Y` union type annotations **must** have `from __future__ import annotations` as the first import. Without it, the `|` syntax raises `TypeError` at runtime on Python < 3.10. Every module in `arma_modlist_tools/` already has it; any new CLI script you add must include it too.

View File

@@ -191,23 +191,29 @@ class ArmaModManagerApp(ctk.CTk):
def run_tool(self, script_args: list[str]) -> None: def run_tool(self, script_args: list[str]) -> None:
"""Run a maintenance script via subprocess, streaming output to Logs.""" """Run a maintenance script via subprocess, streaming output to Logs."""
import os
script = script_args[0] script = script_args[0]
extra = script_args[1:] extra = script_args[1:]
def worker() -> None: def worker() -> None:
self.post_log(f"\n{''*50}\n {' '.join(script_args)}\n{''*50}\n") self.post_log(f"\n{''*50}\n {' '.join(script_args)}\n{''*50}\n")
try: try:
result = subprocess.run( env = os.environ.copy()
[sys.executable, str(PROJECT_ROOT / script)] + extra, env["PYTHONUNBUFFERED"] = "1"
capture_output=True, text=True, cwd=str(PROJECT_ROOT), proc = subprocess.Popen(
[sys.executable, "-u", str(PROJECT_ROOT / script)] + extra,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
cwd=str(PROJECT_ROOT),
env=env,
) )
if result.stdout: for line in iter(proc.stdout.readline, ""):
self.post_log(result.stdout) self.post_log(line)
if result.stderr: proc.wait()
self.post_log(result.stderr) ok = proc.returncode == 0
ok = result.returncode == 0
self.post_log( self.post_log(
f"\n{'✓ Done' if ok else f'✗ Exited with code {result.returncode}'}.\n" f"\n{'✓ Done' if ok else f'✗ Exited with code {proc.returncode}'}.\n"
) )
except Exception as e: except Exception as e:
self.post_log(f"\n✗ Failed to start {script}: {e}\n") self.post_log(f"\n✗ Failed to start {script}: {e}\n")