From eb45a64ce72318f7b469375bae66ea3c6fe5eeee Mon Sep 17 00:00:00 2001 From: Research Assistant Date: Mon, 11 May 2026 19:16:18 +0800 Subject: [PATCH] fix: force UTF-8 encoding for all subprocess and stdout on Windows, fix pre-existing logger bug --- paperforge/__main__.py | 3 +++ paperforge/setup_wizard.py | 36 ++++++++++++++++++++++++++++++------ paperforge/worker/status.py | 1 + 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/paperforge/__main__.py b/paperforge/__main__.py index b4a13235..15d263df 100644 --- a/paperforge/__main__.py +++ b/paperforge/__main__.py @@ -5,4 +5,7 @@ import sys from paperforge.cli import main if __name__ == "__main__": + if sys.platform == "win32": + sys.stdout.reconfigure(encoding="utf-8") + sys.stderr.reconfigure(encoding="utf-8") sys.exit(main()) diff --git a/paperforge/setup_wizard.py b/paperforge/setup_wizard.py index 33f854bf..ac394865 100644 --- a/paperforge/setup_wizard.py +++ b/paperforge/setup_wizard.py @@ -118,7 +118,11 @@ class EnvChecker: def install_dependencies(self) -> bool: deps = ["requests", "pymupdf", "pillow"] try: - subprocess.run([sys.executable, "-m", "pip", "install"] + deps, check=True, capture_output=True, encoding="utf-8", errors="replace") + subprocess.run( + [sys.executable, "-m", "pip", "install"] + deps, + check=True, capture_output=True, + encoding="utf-8", errors="replace", + ) return True except subprocess.CalledProcessError: return False @@ -178,7 +182,12 @@ class EnvChecker: return p # 4. 通过 where 命令检测 try: - result = subprocess.run(["where", "zotero"], capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=5) + result = subprocess.run( + ["where", "zotero"], + capture_output=True, text=True, + encoding="utf-8", errors="replace", + timeout=5, + ) if result.returncode == 0: for line in result.stdout.strip().split("\n"): p = Path(line.strip()) @@ -196,7 +205,12 @@ class EnvChecker: return p # 通过 which 检测 try: - result = subprocess.run(["which", "zotero"], capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=5) + result = subprocess.run( + ["which", "zotero"], + capture_output=True, text=True, + encoding="utf-8", errors="replace", + timeout=5, + ) if result.returncode == 0: return Path(result.stdout.strip()) except Exception: @@ -213,7 +227,12 @@ class EnvChecker: if p.exists(): return p try: - result = subprocess.run(["which", "zotero"], capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=5) + result = subprocess.run( + ["which", "zotero"], + capture_output=True, text=True, + encoding="utf-8", errors="replace", + timeout=5, + ) if result.returncode == 0: return Path(result.stdout.strip()) except Exception: @@ -774,7 +793,10 @@ def headless_setup( timeout=120, ) if result.returncode != 0: - logger.warning("PyPI install failed, falling back to git: %s", result.stderr[:200]) + print( + f" [WARN] PyPI install failed, falling back to git: {result.stderr[:200]}", + file=sys.stderr, + ) result = subprocess.run( [sys.executable, "-m", "pip", "install", "--upgrade"] + git_target, capture_output=True, @@ -812,7 +834,6 @@ def headless_setup( "OCR dir": (pf_path / "ocr").exists(), "paperforge.json": pf_json.exists(), "Obsidian plugin": (vault / ".obsidian" / "plugins" / "paperforge" / "main.js").exists(), - "AGENTS.md": (vault / "AGENTS.md").exists(), } failed = [k for k, v in checks.items() if not v] if failed: @@ -870,4 +891,7 @@ def main(argv: list[str] | None = None) -> int: if __name__ == "__main__": + if sys.platform == "win32": + sys.stdout.reconfigure(encoding="utf-8") + sys.stderr.reconfigure(encoding="utf-8") raise SystemExit(main()) diff --git a/paperforge/worker/status.py b/paperforge/worker/status.py index 0ee73220..b27c0310 100644 --- a/paperforge/worker/status.py +++ b/paperforge/worker/status.py @@ -279,6 +279,7 @@ def _resolve_plugin_interpreter(vault: Path, plugin_data: dict) -> tuple[str, st try: cmd = [path] + extra + ["--version"] result = subprocess.run(cmd, capture_output=True, timeout=5, text=True, encoding="utf-8", errors="replace") + if result.returncode == 0 and "Python" in (result.stdout or ""): return (path, "auto-detected", extra) except (subprocess.TimeoutExpired, FileNotFoundError, PermissionError, OSError): continue